adding phy layer support for mbms

master
Justin Tallon 7 years ago committed by Andre Puschmann
parent 95000edfd8
commit 774a456e31

@ -27,7 +27,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/select.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
@ -38,10 +40,11 @@
#define UE_CRNTI 0x1234
#define M_CRNTI 0xFFFD
#ifndef DISABLE_RF
#include "srslte/phy/rf/rf.h"
#include "srslte/phy/common/phy_common.h"
srslte_rf_t rf;
#else
#warning Compiling pdsch_ue with no RF support
@ -63,33 +66,43 @@ srslte_cell_t cell = {
SRSLTE_PHICH_R_1 // PHICH resources
};
uint16_t c = -1;
int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device
uint32_t cfi = 1;
uint32_t cfi = 2;
uint32_t mcs_idx = 1, last_mcs_idx = 1;
int nof_frames = -1;
char mimo_type_str[32] = "single";
uint32_t nof_tb = 1;
uint32_t multiplex_pmi = 0;
uint32_t multiplex_nof_layers = 1;
int mbsfn_area_id = -1;
char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
bool null_file_sink=false;
srslte_filesink_t fsink;
srslte_ofdm_t ifft;
srslte_ofdm_t ifft_mbsfn;
srslte_pbch_t pbch;
srslte_pcfich_t pcfich;
srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_pmch_t pmch;
srslte_pdsch_cfg_t pmch_cfg;
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
srslte_regs_t regs;
srslte_ra_dl_dci_t ra_dl;
int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0};
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL};
int sf_n_re, sf_n_samples;
pthread_t net_thread;
@ -99,8 +112,13 @@ bool net_packet_ready = false;
srslte_netsource_t net_source;
srslte_netsink_t net_sink;
int prbset_num = 1, last_prbset_num = 1;
int prbset_orig = 0;
//#define DATA_BUFF_SZ 1024*128
//uint8_t data[8*DATA_BUFF_SZ], data2[DATA_BUFF_SZ];
//uint8_t data_tmp[DATA_BUFF_SZ];
#define DATA_BUFF_SZ 1024*1024
uint8_t *data[2], data2[DATA_BUFF_SZ];
@ -121,6 +139,7 @@ void usage(char *prog) {
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-M MBSFN area id [Default %d]\n", mbsfn_area_id);
printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi);
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers);
@ -132,7 +151,8 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) {
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwM")) != -1) {
switch (opt) {
case 'a':
rf_args = argv[optind];
@ -173,6 +193,9 @@ void parse_args(int argc, char **argv) {
case 'w':
multiplex_nof_layers = (uint32_t) atoi(argv[optind]);
break;
case 'M':
mbsfn_area_id = atoi(argv[optind]);
break;
case 'v':
srslte_verbose++;
break;
@ -245,6 +268,7 @@ void base_init() {
bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples);
}
/* open file or USRP */
if (output_file_name) {
if (strcmp(output_file_name, "NULL")) {
@ -291,7 +315,15 @@ void base_init() {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2);
srslte_ofdm_set_normalize(&ifft, true);
srslte_ofdm_set_normalize(&ifft_mbsfn, true);
if (srslte_pbch_init(&pbch)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
@ -301,11 +333,13 @@ void base_init() {
exit(-1);
}
if (srslte_regs_init(&regs, cell)) {
fprintf(stderr, "Error initiating regs\n");
exit(-1);
}
if (srslte_pcfich_init(&pcfich, 1)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
@ -340,6 +374,14 @@ void base_init() {
srslte_pdsch_set_rnti(&pdsch, UE_CRNTI);
if(mbsfn_area_id > -1){
if (srslte_pmch_init(&pmch, cell.nof_prb)) {
fprintf(stderr, "Error creating PMCH object\n");
}
srslte_pmch_set_area_id(&pmch, mbsfn_area_id);
}
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffers[i]) {
@ -354,6 +396,7 @@ void base_init() {
}
}
void base_free() {
int i;
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
@ -366,9 +409,13 @@ void base_free() {
srslte_pdcch_free(&pdcch);
srslte_regs_free(&regs);
srslte_pbch_free(&pbch);
if(mbsfn_area_id > -1){
srslte_pmch_free(&pmch);
}
srslte_ofdm_tx_free(&ifft_mbsfn);
srslte_ofdm_tx_free(&ifft);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data[i]) {
free(data[i]);
@ -481,7 +528,7 @@ int update_radl() {
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &dummy_grant);
srslte_ra_dl_grant_to_nbits(&dummy_grant, cfi, cell, 0, &dummy_nbits);
srslte_ra_dl_grant_fprint(stdout, &dummy_grant);
dummy_grant.sf_type = SRSLTE_SF_NORM;
if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) {
printf("\nTransmission mode key table:\n");
printf(" Mode | 1TB | 2TB |\n");
@ -596,6 +643,7 @@ int update_control() {
}
}
/** Function run in a separate thread to receive UDP data */
void *net_thread_fnc(void *arg) {
int n;
@ -633,6 +681,7 @@ void *net_thread_fnc(void *arg) {
return NULL;
}
int main(int argc, char **argv) {
int nf=0, sf_idx=0, N_id_2=0;
cf_t pss_signal[SRSLTE_PSS_LEN];
@ -645,7 +694,8 @@ int main(int argc, char **argv) {
srslte_dci_msg_t dci_msg;
srslte_dci_location_t locations[SRSLTE_NSUBFRAMES_X_FRAME][30];
uint32_t sfn;
srslte_chest_dl_t est;
srslte_refsignal_t csr_refs;
srslte_refsignal_t mbsfn_refs;
#ifdef DISABLE_RF
if (argc < 3) {
@ -674,21 +724,31 @@ int main(int argc, char **argv) {
srslte_pss_generate(pss_signal, N_id_2);
srslte_sss_generate(sss_signal0, sss_signal5, cell.id);
/* Generate CRS signals */
if (srslte_chest_dl_init(&est, cell.nof_prb)) {
/* Generate reference signals */
if(srslte_refsignal_cs_init(&csr_refs, cell.nof_prb)) {
fprintf(stderr, "Error initializing equalizer\n");
exit(-1);
}
if (srslte_chest_dl_set_cell(&est, cell)) {
if(mbsfn_area_id > -1) {
if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell, mbsfn_area_id)) {
fprintf(stderr, "Error initializing equalizer\n");
exit(-1);
}
}
if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){
fprintf(stderr, "Error setting cell\n");
exit(-1);
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
sf_symbols[i] = sf_buffer[i%cell.nof_ports];
slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
}
#ifndef DISABLE_RF
@ -737,7 +797,6 @@ int main(int argc, char **argv) {
/* 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;
@ -747,6 +806,7 @@ int main(int argc, char **argv) {
srslte_softbuffer_tx_reset(softbuffers[i]);
}
#ifndef DISABLE_RF
bool start_of_burst = true;
#endif
@ -756,7 +816,7 @@ int main(int argc, char **argv) {
/* Set Antenna port resource elements to zero */
bzero(sf_symbols[0], sizeof(cf_t) * sf_n_re);
/* Populate Synchronization signals if required */
if (sf_idx == 0 || sf_idx == 5) {
srslte_pss_put_slot(pss_signal, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM);
srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb,
@ -768,9 +828,12 @@ int main(int argc, char **argv) {
memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re);
}
/* Put reference signals */
if(sf_idx == 1 && mbsfn_area_id > -1){
srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]);
} else {
for (i = 0; i < cell.nof_ports; i++) {
srslte_refsignal_cs_put_sf(cell, (uint32_t) i, est.csr_signal.pilots[i / 2][sf_idx], sf_symbols[i]);
srslte_refsignal_cs_put_sf(cell, (uint32_t) i, csr_refs.pilots[i / 2][sf_idx], sf_symbols[i]);
}
}
srslte_pbch_mib_pack(&cell, sfn, bch_payload);
@ -809,6 +872,7 @@ int main(int argc, char **argv) {
}
if (send_data) {
if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH
srslte_dci_format_t dci_format;
switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
@ -854,23 +918,70 @@ int main(int argc, char **argv) {
if (net_port > 0 && net_packet_ready) {
if (null_file_sink) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (pdsch_cfg.grant.tb_en[tb]) {
srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs);
if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) {
fprintf(stderr, "Error sending data through UDP socket\n");
}
}
}
net_packet_ready = false;
sem_post(&net_sem);
}
}else{ // We're sending MCH on subframe 1 - PDCCH + PMCH
/* Encode PDCCH */
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false);
if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
exit(-1);
}
/* Configure pmch_cfg parameters */
srslte_ra_dl_grant_t grant;
grant.nof_tb = 1;
grant.mcs[0].idx = 2;
grant.mcs[0].mod = SRSLTE_MOD_QPSK;
grant.nof_prb = cell.nof_prb;
grant.sf_type = SRSLTE_SF_MBSFN;
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb);
for(int i = 0; i < 2; i++){
for(int j = 0; j < grant.nof_prb; j++){
grant.prb_idx[i][j] = true;
}
}
if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) {
fprintf(stderr, "Error configuring PMCH\n");
exit(-1);
}
/* Encode PMCH */
if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data[0], mbsfn_area_id, 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[0], data_tmp, pmch_cfg.grant.mcs[0].tbs);
if (srslte_netsink_write(&net_sink, data_tmp, 1+(pmch_cfg.grant.mcs[0].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 */
if(sf_idx != 1 || mbsfn_area_id < 0){
for (i = 0; i < cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]);
}
}else{
srslte_ofdm_tx_sf(&ifft_mbsfn, sf_buffer[0], output_buffer[0]);
}
/* send to file or usrp */
if (output_file_name) {

@ -36,10 +36,8 @@
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <srslte/srslte.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include <srslte/phy/phch/ra.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/phy/io/filesink.h"
#include "srslte/srslte.h"
#define ENABLE_AGC_DEFAULT
@ -69,7 +67,7 @@ sem_t plot_sem;
uint32_t plot_sf_idx=0;
bool plot_track = true;
#endif
char *output_file_name;
#define PRINT_CHANGE_SCHEDULIGN
//#define CORRECT_SAMPLE_OFFSET
@ -101,6 +99,8 @@ typedef struct {
int net_port_signal;
char *net_address_signal;
int decimate;
int mbsfn_area_id;
uint8_t non_mbsfn_region;
int verbose;
}prog_args_t;
@ -132,10 +132,12 @@ void args_default(prog_args_t *args) {
args->net_address_signal = "127.0.0.1";
args->decimate = 0;
args->cpu_affinity = -1;
args->mbsfn_area_id = -1;
args->non_mbsfn_region = 2;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [agpPoOcildDnruv] -f rx_frequency (in Hz) | -i input_file\n", prog);
printf("Usage: %s [agpPoOcildDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog);
#ifndef DISABLE_RF
printf("\t-a RF args [Default %s]\n", args->rf_args);
printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant);
@ -169,13 +171,15 @@ void usage(prog_args_t *args, char *prog) {
printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal);
printf("\t-u remote TCP port to send data (-1 does nothing with it) [Default %d]\n", args->net_port);
printf("\t-U remote TCP address to send data [Default %s]\n", args->net_address);
printf("\t-M MBSFN area id [Default %s]\n", args->mbsfn_area_id);
printf("\t-N Non-MBSFN region [Default %s]\n", args->non_mbsfn_region);
printf("\t-v [set srslte_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, "aAoglipPcOCtdDnvrfuUsSZy")) != -1) {
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZyWMN")) != -1) {
switch (opt) {
case 'i':
args->input_file_name = argv[optind];
@ -250,6 +254,15 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'y':
args->cpu_affinity = atoi(argv[optind]);
break;
case 'W':
output_file_name = argv[optind];
break;
case 'M':
args->mbsfn_area_id = atoi(argv[optind]);
break;
case 'N':
args->non_mbsfn_region = atoi(argv[optind]);
break;
default:
usage(args, argv[0]);
exit(-1);
@ -278,6 +291,7 @@ void sig_int_handler(int signo)
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL};
#ifndef DISABLE_RF
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
@ -304,8 +318,8 @@ prog_args_t prog_args;
uint32_t sfn = 0; // system frame number
srslte_netsink_t net_sink, net_sink_signal;
/* Useful macros for printing lines which will disappear */
#define PRINT_LINE_INIT() int this_nof_lines = 0; static int prev_nof_lines = 0
#define PRINT_LINE(_fmt, ...) printf("\033[K" _fmt "\n", ##__VA_ARGS__); this_nof_lines++
#define PRINT_LINE_RESET_CURSOR() printf("\033[%dA", this_nof_lines); prev_nof_lines = this_nof_lines
@ -317,6 +331,7 @@ int main(int argc, char **argv) {
srslte_cell_t cell;
int64_t sf_cnt;
srslte_ue_mib_t ue_mib;
#ifndef DISABLE_RF
srslte_rf_t rf;
#endif
@ -335,6 +350,7 @@ int main(int argc, char **argv) {
}
}
if(prog_args.cpu_affinity > -1) {
cpu_set_t cpuset;
@ -403,6 +419,7 @@ int main(int argc, char **argv) {
srslte_rf_set_rx_freq(&rf, prog_args.rf_freq + prog_args.file_offset_freq);
srslte_rf_rx_wait_lo_locked(&rf);
uint32_t ntrial=0;
do {
ret = rf_search_and_decode_mib(&rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo);
@ -518,6 +535,11 @@ int main(int argc, char **argv) {
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti);
/* Configure MBSFN area id and non-MBSFN Region */
if (prog_args.mbsfn_area_id > -1) {
srslte_ue_dl_set_mbsfn_area_id(&ue_dl, prog_args.mbsfn_area_id);
srslte_ue_dl_set_non_mbsfn_region(&ue_dl, prog_args.non_mbsfn_region);
}
/* Initialize subframe counter */
sf_cnt = 0;
@ -592,7 +614,6 @@ int main(int argc, char **argv) {
}
}
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
@ -605,9 +626,12 @@ int main(int argc, char **argv) {
/* srslte_ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync);
switch (state) {
case DECODE_MIB:
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
if (sfidx == 0) {
n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset);
if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n");
@ -626,15 +650,14 @@ int main(int argc, char **argv) {
decode_pdsch = true;
} else {
/* We are looking for SIB1 Blocks, search only in appropiate places */
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
if ((sfidx == 5 && (sfn%2)==0) || sfidx == 1) {
decode_pdsch = true;
} else {
decode_pdsch = false;
}
}
INFO("Attempting DL decode SFN=%d\n", sfn);
if (decode_pdsch) {
if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
if (cell.nof_ports == 1) {
/* Transmission mode 1 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
@ -654,15 +677,29 @@ int main(int argc, char **argv) {
}
}
}
}else{ // MBSFN subframe
n = srslte_ue_dl_decode_mbsfn(&ue_dl,
sf_buffer,
data[0],
sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
if(n>0){
if(output_file_name){
//srslte_filesink_init(&sink, output_file_name, SRSLTE_BYTE_BIN);
// srslte_filesink_write(&sink, data, n);
//srslte_filesink_free(&sink);
}
INFO("mbsfn PDU size is %d\n", n);
}
}
if (n < 0) {
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
} else if (n > 0) {
/* Send data if socket active */
if (prog_args.net_port > 0) {
if(sfidx == 1) {
srslte_netsink_write(&net_sink, data[0], 1+(n-1)/8);
} else {
// FIXME: UDP Data transmission does not work
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (ue_dl.pdsch_cfg.grant.tb_en[tb]) {
@ -670,7 +707,7 @@ int main(int argc, char **argv) {
}
}
}
}
#ifdef PRINT_CHANGE_SCHEDULIGN
if (ue_dl.dl_dci.mcs_idx != old_dl_dci.mcs_idx ||
memcmp(&ue_dl.dl_dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srslte_ra_type0_t)) ||
@ -689,6 +726,7 @@ int main(int argc, char **argv) {
nof_trials++;
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f);
rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f);
rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f);
@ -696,6 +734,7 @@ int main(int argc, char **argv) {
enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f);
uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f);
nframes++;
if (isnan(rsrq)) {
rsrq = 0;
@ -704,15 +743,15 @@ int main(int argc, char **argv) {
noise = 0;
}
if (isnan(rsrp0)) {
rsrp1 = 0;
rsrp0 = 0;
}
if (isnan(rsrp0)) {
if (isnan(rsrp1)) {
rsrp1 = 0;
}
}
// Plot and Printf
if (srslte_ue_sync_get_sfidx(&ue_sync) == 5 && sfn % 20 == 0) {
if (sfidx == 5) {
float gain = prog_args.rf_gain;
if (gain < 0) {
gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc));
@ -733,7 +772,10 @@ int main(int argc, char **argv) {
PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise));
PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate);
PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials));
PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total);
PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total);
if(prog_args.mbsfn_area_id > -1){
PRINT_LINE(" PMCH-BLER: %5.2f%%", (float) 100 * ue_dl.pmch_pkt_errors/ue_dl.pmch_pkts_total);
}
PRINT_LINE(" TB 0: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[0].idx,
ue_dl.pdsch_cfg.grant.mcs[0].tbs);
PRINT_LINE(" TB 1: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[1].idx,
@ -775,14 +817,17 @@ int main(int argc, char **argv) {
PRINT_LINE("Press enter maximum printing debug log of 1 subframe.");
PRINT_LINE("");
PRINT_LINE_RESET_CURSOR();
}
break;
}
if (srslte_ue_sync_get_sfidx(&ue_sync) == 9) {
if (sfidx == 9) {
sfn++;
if (sfn == 1024) {
sfn = 0;
PRINT_LINE_ADVANCE_CURSOR();
ue_dl.pdsch_pkt_errors = 0;
ue_dl.pdsch_pkts_total = 0;
/*
ue_dl.pkt_errors = 0;
ue_dl.pkts_total = 0;
@ -794,7 +839,7 @@ int main(int argc, char **argv) {
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) {
if ((sfn%4) == 0 && decode_pdsch) {
if ((sfn%3) == 0 && decode_pdsch) {
plot_sf_idx = srslte_ue_sync_get_sfidx(&ue_sync);
plot_track = true;
sem_post(&plot_sem);
@ -816,7 +861,6 @@ int main(int argc, char **argv) {
sf_cnt++;
} // Main loop
printf("\033[30B\n");
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) {
@ -845,6 +889,7 @@ int main(int argc, char **argv) {
srslte_rf_close(&rf);
}
#endif
printf("\nBye\n");
exit(0);
}

@ -60,7 +60,10 @@ typedef enum {
typedef struct {
srslte_cell_t cell;
srslte_refsignal_cs_t csr_signal;
srslte_refsignal_t csr_refs;
srslte_refsignal_t **mbsfn_refs;
cf_t *pilot_estimates;
cf_t *pilot_estimates_average;
cf_t *pilot_recv_signal;
@ -75,7 +78,7 @@ typedef struct {
srslte_interp_linsrslte_vec_t srslte_interp_linvec;
srslte_interp_lin_t srslte_interp_lin;
srslte_interp_lin_t srslte_interp_lin_mbsfn;
float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
@ -96,9 +99,13 @@ SRSLTE_API int srslte_chest_dl_init(srslte_chest_dl_t *q,
SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q);
SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q,
uint16_t mbsfn_area_id);
SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q,
srslte_cell_t cell);
SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
float *filter,
uint32_t filter_len);
@ -109,6 +116,8 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q,
SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
srslte_chest_dl_noise_alg_t noise_estimation_alg);
SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
@ -120,6 +129,14 @@ SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t *q,
cf_t *ce[SRSLTE_MAX_PORTS],
uint32_t sf_idx);
SRSLTE_API int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t nof_rx_antennas,
uint16_t mbsfn_area_id);
SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q,
cf_t *input,
cf_t *ce,

@ -40,25 +40,34 @@
// Number of references in a subframe: there are 2 symbols for port_id=0,1 x 2 slots x 2 refs per prb
#define SRSLTE_REFSIGNAL_NUM_SF(nof_prb, port_id) (((port_id)<2?8:4)*(nof_prb))
#define SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb, port_id) ((2 + 18)*(nof_prb))
#define SRSLTE_REFSIGNAL_MAX_NUM_SF(nof_prb) SRSLTE_REFSIGNAL_NUM_SF(nof_prb, 0)
#define SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(nof_prb) SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb,0)
#define SRSLTE_REFSIGNAL_PILOT_IDX(i,l,cell) (2*cell.nof_prb*(l)+(i))
#define SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i,l,cell) ((6*cell.nof_prb*(l)+(i)))
/** Cell-Specific Reference Signal */
typedef struct SRSLTE_API {
srslte_cell_t cell;
cf_t *pilots[2][SRSLTE_NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3
} srslte_refsignal_cs_t;
srslte_sf_t type;
uint16_t mbsfn_area_id;
} srslte_refsignal_t;
SRSLTE_API int srslte_refsignal_cs_init(srslte_refsignal_cs_t *q,
SRSLTE_API int srslte_refsignal_cs_init(srslte_refsignal_t *q,
uint32_t max_prb);
SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q,
SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q,
srslte_cell_t cell);
SRSLTE_API void srslte_refsignal_cs_free(srslte_refsignal_cs_t *q);
SRSLTE_API void srslte_refsignal_free(srslte_refsignal_t *q);
SRSLTE_API int srslte_refsignal_cs_put_sf(srslte_cell_t cell,
uint32_t port_id,
@ -84,4 +93,29 @@ SRSLTE_API uint32_t srslte_refsignal_cs_v(uint32_t port_id,
SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id);
SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t *q, srslte_cell_t cell,
uint16_t mbsfn_area_id);
SRSLTE_API int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell,
uint32_t port_id,
cf_t *sf_symbols,
cf_t *pilots);
SRSLTE_API uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l);
SRSLTE_API uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l);
SRSLTE_API uint32_t srslte_refsignal_mbsfn_nof_symbols();
SRSLTE_API int srslte_refsignal_mbsfn_put_sf(srslte_cell_t cell,
uint32_t port_id,
cf_t *cs_pilots,
cf_t *mbsfn_pilots,
cf_t *sf_symbols);
SRSLTE_API int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q,
srslte_cell_t cell,
uint32_t N_mbsfn_id);
#endif

@ -63,7 +63,11 @@
#define SRSLTE_LTE_CRC16 0x11021
#define SRSLTE_LTE_CRC8 0x19B
#define SRSLTE_MAX_MBSFN_AREA_IDS 256
#define SRSLTE_PMCH_RV 0
typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t;
typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t;
#define SRSLTE_CRNTI_START 0x000B
@ -130,6 +134,13 @@ typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t;
|| l == SRSLTE_CP_NSYMB(cp) - 3)
#define SRSLTE_SYMBOL_HAS_REF_MBSFN(l, s) ((l == 2 && s == 0) || (l == 0 && s == 1) || (l == 4 && s == 1))
#define SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(non_mbsfn_region,symbol_sz) ((non_mbsfn_region == 1)?(SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)):(2*SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)- SRSLTE_CP_LEN_NORM(1, symbol_sz)))
#define SRSLTE_NOF_LTE_BANDS 38
#define SRSLTE_DEFAULT_MAX_FRAMES_PBCH 500
@ -157,6 +168,7 @@ typedef enum {
SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */
SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */
SRSLTE_RNTI_PCH, /* Paging RNTI */
SRSLTE_RNTI_MBSFN,
SRSLTE_RNTI_NOF_TYPES
} srslte_rnti_type_t;

@ -94,4 +94,10 @@ SRSLTE_API int srslte_sequence_pucch(srslte_sequence_t *seq,
uint16_t rnti,
uint32_t nslot,
uint32_t cell_id);
SRSLTE_API int srslte_sequence_pmch(srslte_sequence_t *seq,
uint32_t nslot,
uint32_t mbsfn_id,
uint32_t len);
#endif

@ -56,6 +56,12 @@ typedef struct SRSLTE_API{
srslte_cp_t cp;
cf_t *tmp; // for removing zero padding
bool mbsfn_subframe;
uint32_t mbsfn_guard_len;
uint32_t nof_symbols_mbsfn;
uint8_t non_mbsfn_region;
bool freq_shift;
float freq_shift_f;
cf_t *shift_buffer;
@ -64,9 +70,22 @@ typedef struct SRSLTE_API{
SRSLTE_API int srslte_ofdm_init_(srslte_ofdm_t *q,
srslte_cp_t cp,
int symbol_sz,
int max_prb,
int nof_prb,
srslte_dft_dir_t dir);
SRSLTE_API int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q,
srslte_cp_t cp,
int symbol_sz,
int nof_prb,
srslte_dft_dir_t dir,
srslte_sf_t sf_type);
SRSLTE_API int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q,
srslte_cp_t cp_type,
uint32_t nof_prb);
SRSLTE_API int srslte_ofdm_rx_init(srslte_ofdm_t *q,
srslte_cp_t cp_type,
uint32_t max_prb);
@ -95,12 +114,22 @@ SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q,
srslte_cp_t cp_type,
uint32_t nof_prb);
SRSLTE_API int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q,
srslte_cp_t cp,
uint32_t nof_prb);
SRSLTE_API void srslte_ofdm_tx_free(srslte_ofdm_t *q);
SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t *q,
cf_t *input,
cf_t *output);
SRSLTE_API void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q,
cf_t *input,
cf_t *output);
SRSLTE_API void srslte_ofdm_tx_sf(srslte_ofdm_t *q,
cf_t *input,
cf_t *output);
@ -111,4 +140,8 @@ SRSLTE_API int srslte_ofdm_set_freq_shift(srslte_ofdm_t *q,
SRSLTE_API void srslte_ofdm_set_normalize(srslte_ofdm_t *q,
bool normalize_enable);
SRSLTE_API void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q,
uint8_t non_mbsfn_region);
#endif

@ -76,7 +76,7 @@ typedef struct SRSLTE_API {
srslte_pdsch_t pdsch;
srslte_phich_t phich;
srslte_refsignal_cs_t csr_signal;
srslte_refsignal_t csr_signal;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_ra_dl_dci_t dl_dci;

@ -0,0 +1,152 @@
/**
*
* \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/.
*
*/
/******************************************************************************
* File: pmch.h
*
* Description: Physical multicast channel
*
* Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 6.5
*****************************************************************************/
#ifndef PMCH_
#define PMCH_
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/mimo/precoding.h"
#include "srslte/phy/mimo/layermap.h"
#include "srslte/phy/modem/mod.h"
#include "srslte/phy/modem/demod_soft.h"
#include "srslte/phy/scrambling/scrambling.h"
#include "srslte/phy/phch/dci.h"
#include "srslte/phy/phch/regs.h"
#include "srslte/phy/phch/sch.h"
#include "srslte/phy/common/sequence.h"
typedef struct {
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
} srslte_pmch_seq_t;
typedef struct SRSLTE_API {
srslte_cbsegm_t cb_segm;
srslte_ra_dl_grant_t grant;
srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS];
uint32_t sf_idx;
} srslte_pmch_cfg_t;
/* PMCH object */
typedef struct SRSLTE_API {
srslte_cell_t cell;
uint32_t nof_rx_antennas;
uint32_t max_re;
/* buffers */
// void buffers are shared for tx and rx
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *symbols[SRSLTE_MAX_PORTS];
cf_t *x[SRSLTE_MAX_PORTS];
cf_t *d;
void *e;
/* tx & rx objects */
srslte_modem_table_t mod[4];
// This is to generate the scrambling seq for multiple MBSFN Area IDs
srslte_pmch_seq_t **seqs;
srslte_sch_t dl_sch;
} srslte_pmch_t;
SRSLTE_API int srslte_pmch_init(srslte_pmch_t *q,
uint32_t max_prb);
SRSLTE_API int srslte_pmch_init_multi(srslte_pmch_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_pmch_free(srslte_pmch_t *q);
SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id);
SRSLTE_API void srslte_pmch_free_area_id(srslte_pmch_t *q, uint16_t area_id);
SRSLTE_API int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart);
SRSLTE_API int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart);
SRSLTE_API int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put);
SRSLTE_API float srslte_pmch_coderate(uint32_t tbs,
uint32_t nof_re);
SRSLTE_API int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg,
srslte_cell_t cell,
srslte_ra_dl_grant_t *grant,
uint32_t cfi,
uint32_t sf_idx);
SRSLTE_API int srslte_pmch_encode(srslte_pmch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer,
uint8_t *data,
uint16_t area_id,
cf_t *sf_symbols[SRSLTE_MAX_PORTS]);
SRSLTE_API int srslte_pmch_decode(srslte_pmch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols,
cf_t *ce[SRSLTE_MAX_PORTS],
float noise_estimate,
uint16_t area_id,
uint8_t *data);
SRSLTE_API int srslte_pmch_decode_multi(srslte_pmch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint16_t area_id,
uint8_t *data);
SRSLTE_API float srslte_pmch_average_noi(srslte_pmch_t *q);
SRSLTE_API uint32_t srslte_pmch_last_noi(srslte_pmch_t *q);
#endif

@ -103,7 +103,11 @@ typedef struct SRSLTE_API {
bool prb_idx[2][SRSLTE_MAX_PRB];
uint32_t nof_prb;
uint32_t Qm[SRSLTE_MAX_CODEWORDS];
uint32_t Qm2[SRSLTE_MAX_CODEWORDS];
srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS];
srslte_ra_mcs_t mcs2[SRSLTE_MAX_CODEWORDS];
uint32_t nof_tb;
srslte_sf_t sf_type;
bool tb_en[SRSLTE_MAX_CODEWORDS];
uint32_t pinfo;
} srslte_ra_dl_grant_t;
@ -290,4 +294,9 @@ SRSLTE_API void srslte_ra_pusch_fprint(FILE *f,
SRSLTE_API void srslte_ra_ul_grant_fprint(FILE *f,
srslte_ra_ul_grant_t *grant);
SRSLTE_API int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb);
SRSLTE_API int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb);
#endif /* RB_ALLOC_H_ */

@ -77,6 +77,7 @@ typedef struct SRSLTE_API {
srslte_uci_cqi_pusch_t uci_cqi;
} srslte_sch_t;
#include "srslte/phy/phch/pmch.h"
SRSLTE_API int srslte_sch_init(srslte_sch_t *q);

@ -48,6 +48,7 @@
#include "srslte/phy/phch/pcfich.h"
#include "srslte/phy/phch/pdcch.h"
#include "srslte/phy/phch/pdsch.h"
#include "srslte/phy/phch/pmch.h"
#include "srslte/phy/phch/pdsch_cfg.h"
#include "srslte/phy/phch/phich.h"
#include "srslte/phy/phch/ra.h"
@ -76,14 +77,17 @@ typedef struct SRSLTE_API {
srslte_pcfich_t pcfich;
srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch;
srslte_pmch_t pmch;
srslte_phich_t phich;
srslte_regs_t regs;
srslte_ofdm_t fft;
srslte_ofdm_t fft_mbsfn;
srslte_chest_dl_t chest;
srslte_cfo_t sfo_correct;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_pdsch_cfg_t pmch_cfg;
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_dci_t dl_dci;
srslte_cell_t cell;
@ -103,9 +107,14 @@ typedef struct SRSLTE_API {
srslte_dci_format_t dci_format;
uint64_t pkt_errors;
uint64_t pkts_total;
uint64_t pdsch_pkt_errors;
uint64_t pdsch_pkts_total;
uint64_t pmch_pkt_errors;
uint64_t pmch_pkts_total;
uint64_t nof_detected;
uint16_t current_rnti;
uint16_t current_mbsfn_area_id;
dci_blind_search_t current_ss_ue[3][10];
dci_blind_search_t current_ss_common[3];
srslte_dci_location_t last_location;
@ -127,15 +136,27 @@ SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q);
SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q,
srslte_cell_t cell);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t *cfi,
srslte_sf_t sf_type);
int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
uint32_t sf_idx,
uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q,
uint32_t sf_idx,
uint32_t *cfi,
srslte_sf_t sf_type);
SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
srslte_ra_dl_grant_t *grant,
uint32_t cfi,
@ -184,6 +205,18 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q,
uint16_t rnti,
bool acks[SRSLTE_MAX_CODEWORDS]);
/* Used by example applications - full PMCH decode for a given MBSFN area ID
* srslte_ue_dl_decode_fft_estimate_multi,
* srslte_chest_dl_get_noise_estimate,
* srslte_ue_dl_cfg_grant,
* srslte_pmch_decode_multi
*/
SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data,
uint32_t tti);
SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q,
uint8_t *ri,
uint8_t *pmi,
@ -203,6 +236,15 @@ SRSLTE_API void srslte_ue_dl_reset(srslte_ue_dl_t *q);
SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q,
uint16_t rnti);
/* Generate signals if required, store in q->current_mbsfn_area_id */
SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q,
uint16_t mbsfn_area_id);
SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q,
uint8_t non_mbsfn_region_length);
SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q,
srslte_softbuffer_rx_t *softbuffer,
uint32_t tti,

@ -81,29 +81,46 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
{
bzero(q, sizeof(srslte_chest_dl_t));
ret = srslte_refsignal_cs_init(&q->csr_signal, max_prb);
ret = srslte_refsignal_cs_init(&q->csr_refs, max_prb);
if (ret != SRSLTE_SUCCESS) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit;
}
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb));
q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t*));
if (!q->mbsfn_refs) {
fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret);
goto clean_exit;
}
int pilot_vec_size;
if(SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb)>SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)) {
pilot_vec_size = SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb);
}else{
pilot_vec_size = SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb);
}
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->tmp_noise) {
perror("malloc");
goto clean_exit;
}
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb));
if (!q->pilot_estimates) {
perror("malloc");
goto clean_exit;
}
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb));
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->pilot_estimates_average) {
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb));
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->pilot_recv_signal) {
perror("malloc");
goto clean_exit;
@ -119,6 +136,11 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
goto clean_exit;
}
if (srslte_interp_linear_init(&q->srslte_interp_lin_mbsfn, 6*max_prb, SRSLTE_NRE/6)) {
fprintf(stderr, "Error initializing interpolator\n");
goto clean_exit;
}
q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->smooth_filter_len = 3;
@ -137,14 +159,25 @@ clean_exit:
void srslte_chest_dl_free(srslte_chest_dl_t *q)
{
srslte_refsignal_cs_free(&q->csr_signal);
int i;
if(&q->csr_refs)
srslte_refsignal_free(&q->csr_refs);
if (q->mbsfn_refs) {
for (i=0; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) {
if (q->mbsfn_refs[i]) {
srslte_refsignal_free(q->mbsfn_refs[i]);
}
}
free(q->mbsfn_refs);
}
if (q->tmp_noise) {
free(q->tmp_noise);
}
srslte_interp_linear_vector_free(&q->srslte_interp_linvec);
srslte_interp_linear_free(&q->srslte_interp_lin);
srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn);
if (q->pilot_estimates) {
free(q->pilot_estimates);
}
@ -157,6 +190,19 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
bzero(q, sizeof(srslte_chest_dl_t));
}
int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_id){
if(!q->mbsfn_refs[mbsfn_area_id]){
q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t));
}
if(q->mbsfn_refs[mbsfn_area_id]) {
if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell, mbsfn_area_id)) {
return SRSLTE_ERROR;
}
}
return SRSLTE_SUCCESS;
}
int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -165,7 +211,7 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
{
if (q->cell.id != cell.id || q->cell.nof_prb == 0) {
memcpy(&q->cell, &cell, sizeof(srslte_cell_t));
ret = srslte_refsignal_cs_set_cell(&q->csr_signal, cell);
ret = srslte_refsignal_cs_set_cell(&q->csr_refs, cell);
if (ret != SRSLTE_SUCCESS) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
return SRSLTE_ERROR;
@ -187,7 +233,6 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
}
ret = SRSLTE_SUCCESS;
}
return ret;
}
@ -253,21 +298,43 @@ static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) {
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id)
static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id, srslte_sf_t ch_mode)
{
/* interpolate the symbols with references in the freq domain */
uint32_t l;
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id);
uint32_t fidx_offset = 0;
/* Interpolate in the frequency domain */
for (l=0;l<nsymbols;l++) {
uint32_t fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
// we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation
for (l=0;l<(nsymbols);l++) {
if (ch_mode == SRSLTE_SF_MBSFN) {
if (l == 0) {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/2-fidx_offset);
} else {
fidx_offset = srslte_refsignal_mbsfn_fidx(l - 1);
srslte_interp_linear_offset(&q->srslte_interp_lin_mbsfn, &pilot_estimates[(2*q->cell.nof_prb) + 6*q->cell.nof_prb*(l - 1)],
&ce[srslte_refsignal_mbsfn_nsymbol(l - 1) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/6-fidx_offset);
}
} else {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/2-fidx_offset);
}
}
/* Now interpolate in the time domain between symbols */
if (ch_mode == SRSLTE_SF_MBSFN) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
} else {
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
if (nsymbols == 4) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
@ -291,8 +358,10 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
}
}
}
}
void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) {
if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) {
if (filter) {
@ -319,9 +388,9 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w)
q->smooth_filter[1] = 1-2*w;
}
static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id) {
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = 2*q->cell.nof_prb;
static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
// Average in the frequency domain
for (int l=0;l<nsymbols;l++) {
@ -341,23 +410,14 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id)
return rssi/nsymbols;
}
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id)
{
/* Get references from the input signal */
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
/* Use the known CSR signal to compute Least-squares estimates */
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_signal.pilots[port_id/2][sf_idx],
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, srslte_sf_t ch_mode){
if (ce != NULL) {
/* Smooth estimates (if applicable) and interpolate */
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) {
interpolate_pilots(q, q->pilot_estimates, ce, port_id);
interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode);
} else {
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id);
interpolate_pilots(q, q->pilot_estimates_average, ce, port_id);
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id, ch_mode);
interpolate_pilots(q, q->pilot_estimates_average, ce, port_id, ch_mode);
}
/* Estimate noise power */
@ -372,7 +432,6 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u
q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input);
}
}
}
/* Compute RSRP for the channel estimates in this port */
@ -381,9 +440,41 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u
/* compute rssi only for port 0 */
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
}
}
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id)
{
/* Get references from the input signal */
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
/* Use the known CSR signal to compute Least-squares estimates */
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx],
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM);
return 0;
}
int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id)
{
/* Use the known CSR signal to compute Least-squares estimates */
srslte_refsignal_mbsfn_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
// estimate for non-mbsfn section of subframe
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx],
q->pilot_estimates, (2*q->cell.nof_prb));
srslte_vec_prod_conj_ccc(q->pilot_recv_signal+(2*q->cell.nof_prb), q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx],
q->pilot_estimates+(2*q->cell.nof_prb), SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb));
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN);
return 0;
}
int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas)
{
@ -411,6 +502,21 @@ int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_
return SRSLTE_SUCCESS;
}
int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas, uint16_t mbsfn_area_id)
{
for (uint32_t rxant_id=0;rxant_id<nof_rx_antennas;rxant_id++) {
for (uint32_t port_id=0;port_id<q->cell.nof_ports;port_id++) {
if (srslte_chest_dl_estimate_port_mbsfn(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id, mbsfn_area_id)) {
return SRSLTE_ERROR;
}
}
}
q->last_nof_antennas = nof_rx_antennas;
return SRSLTE_SUCCESS;
}
float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) {
float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) {

@ -75,17 +75,44 @@ uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx)
uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id)
{
uint32_t ret;
if (port_id < 2) {
return 4;
ret = 4;
} else {
return 2;
ret = 2;
}
return ret;
}
uint32_t srslte_refsignal_mbsfn_nof_symbols()
{
if(false){
return 3;
}else{
return 3;
}
}
inline uint32_t srslte_refsignal_cs_fidx(srslte_cell_t cell, uint32_t l, uint32_t port_id, uint32_t m) {
return 6*m + ((srslte_refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6);
}
inline uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l)
{
uint32_t ret = 0;
if(l == 0){
ret = 0;
}else if (l == 1){
ret = 1;
}else if(l == 2){
ret = 0;
}
return ret;
}
inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t port_id) {
if (port_id < 2) {
if (l % 2) {
@ -97,11 +124,104 @@ inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t
return 1+l*SRSLTE_CP_NSYMB(cp);
}
}
inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l)
{
uint32_t ret = 0;
if(l == 0){
ret = 2;
} else if (l == 1) {
ret = 6;
} else if (l == 2){
ret = 10;
}
return ret;
}
int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q, srslte_cell_t cell, uint32_t N_mbsfn_id)
{
uint32_t c_init;
uint32_t i, ns, l, p;
uint32_t mp;
int ret = SRSLTE_ERROR;
srslte_sequence_t seq_mbsfn;
bzero(&seq_mbsfn, sizeof(srslte_sequence_t));
if (srslte_sequence_init(&seq_mbsfn, 20* SRSLTE_MAX_PRB)) {
goto free_and_exit;
}
for(ns=0; ns<SRSLTE_NSUBFRAMES_X_FRAME;ns++){
for(p=0;p<2;p++) {
uint32_t nsymbols = 3; // replace with function
for(l=0;l<nsymbols;l++) {
uint32_t lp = (srslte_refsignal_mbsfn_nsymbol(l))%6;
uint32_t slot =(l)?(ns*2+1):(ns*2);
c_init = 512*(7*(slot+1)+lp+1)*(2*N_mbsfn_id + 1) + N_mbsfn_id;
srslte_sequence_set_LTE_pr(&seq_mbsfn,SRSLTE_MAX_PRB*20 ,c_init);
for(i=0;i< 6*q->cell.nof_prb;i++) {
mp = i + 3*(SRSLTE_MAX_PRB - cell.nof_prb);
q->pilots[p][ns][ SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i, l ,q->cell)] = (1 - 2 * (float) seq_mbsfn.c[2 * mp]) / sqrt(2) +_Complex_I * (1 - 2 * (float) seq_mbsfn.c[2 * mp + 1]) / sqrt(2);
}
}
}
}
srslte_sequence_free(&seq_mbsfn);
ret = SRSLTE_SUCCESS;
free_and_exit:
if (ret == SRSLTE_ERROR) {
srslte_sequence_free(&seq_mbsfn);
srslte_refsignal_free(q);
}
return ret;
}
int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t i, p;
if (q != NULL &&
srslte_cell_isvalid(&cell))
{
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_refsignal_t));
q->cell = cell;
q->type = SRSLTE_SF_MBSFN;
q->mbsfn_area_id = mbsfn_area_id;
for (p=0;p<2;p++) {
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * q->cell.nof_prb * 18);
if (!q->pilots[p][i]) {
perror("malloc");
goto free_and_exit;
}
}
}
if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) {
goto free_and_exit;
}
ret = SRSLTE_SUCCESS;
}
free_and_exit:
if (ret == SRSLTE_ERROR) {
srslte_refsignal_free(q);
}
return ret;
}
/** Allocates memory for the 20 slots in a subframe
*/
int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb)
int srslte_refsignal_cs_init(srslte_refsignal_t * q, uint32_t max_prb)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -109,7 +229,6 @@ int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb)
if (q != NULL)
{
ret = SRSLTE_ERROR;
for (int p=0;p<2;p++) {
for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(max_prb, 2*p));
@ -123,7 +242,7 @@ int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb)
}
free_and_exit:
if (ret == SRSLTE_ERROR) {
srslte_refsignal_cs_free(q);
srslte_refsignal_free(q);
}
return ret;
}
@ -131,7 +250,7 @@ free_and_exit:
/** Allocates and precomputes the Cell-Specific Reference (CSR) signal for
* the 20 slots in a subframe
*/
int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, srslte_cell_t cell)
int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, srslte_cell_t cell)
{
uint32_t c_init;
@ -188,7 +307,7 @@ int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, srslte_cell_t cell)
}
/** Deallocates a srslte_refsignal_cs_t object allocated with srslte_refsignal_cs_init */
void srslte_refsignal_cs_free(srslte_refsignal_cs_t * q)
void srslte_refsignal_free(srslte_refsignal_t * q)
{
for (int p=0;p<2;p++) {
for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
@ -197,10 +316,12 @@ void srslte_refsignal_cs_free(srslte_refsignal_cs_t * q)
}
}
}
bzero(q, sizeof(srslte_refsignal_cs_t));
bzero(q, sizeof(srslte_refsignal_t));
}
/* Maps a reference signal initialized with srslte_refsignal_cs_init() into an array of subframe symbols */
int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, cf_t *pilots, cf_t *sf_symbols)
{
@ -228,6 +349,45 @@ int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, cf_t *pilot
}
}
SRSLTE_API int srslte_refsignal_mbsfn_put_sf(srslte_cell_t cell,
uint32_t port_id,
cf_t *cs_pilots,
cf_t *mbsfn_pilots,
cf_t *sf_symbols)
{
uint32_t i, l;
uint32_t fidx;
if (srslte_cell_isvalid(&cell) &&
srslte_portid_isvalid(port_id) &&
cs_pilots != NULL &&
mbsfn_pilots != NULL &&
sf_symbols != NULL)
{
// adding CS refs for the non-mbsfn section of the sub-frame
fidx = ((srslte_refsignal_cs_v(port_id, 0) + (cell.id % 6)) % 6);
for (i = 0; i < 2*cell.nof_prb; i++) {
sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, 0, fidx)] = cs_pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i,0,cell)];
fidx += SRSLTE_NRE/2; // 1 reference every 6 RE
}
for (l = 0; l<srslte_refsignal_mbsfn_nof_symbols(); l++) {
uint32_t nsymbol = srslte_refsignal_mbsfn_nsymbol(l);
fidx = srslte_refsignal_mbsfn_fidx(l);
for (i = 0; i < 6*cell.nof_prb; i++) {
sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)] = mbsfn_pilots[SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i,l,cell)];
fidx += SRSLTE_NRE/6;
}
}
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/** Copies the RE containing references from an array of subframe symbols to the pilots array. */
int srslte_refsignal_cs_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_symbols, cf_t *pilots)
{
@ -254,4 +414,39 @@ int srslte_refsignal_cs_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_sy
}
}
int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_symbols, cf_t *pilots)
{
uint32_t i, l;
uint32_t fidx;
uint32_t nsymbol;
if (srslte_cell_isvalid(&cell) &&
srslte_portid_isvalid(port_id) &&
pilots != NULL &&
sf_symbols != NULL)
{
// getting refs from non mbsfn section of subframe
nsymbol = srslte_refsignal_cs_nsymbol(0, cell.cp, port_id);
fidx = ((srslte_refsignal_cs_v(port_id, 0) + (cell.id % 6)) % 6);
for (i = 0; i < 2*cell.nof_prb; i++) {
pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i,0,cell)] = sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)];
fidx += SRSLTE_NRE/2; // 2 references per PRB
}
for (l = 0; l< srslte_refsignal_mbsfn_nof_symbols() ;l++){
nsymbol = srslte_refsignal_mbsfn_nsymbol(l);
fidx = srslte_refsignal_mbsfn_fidx(l);
for (i = 0; i < 6*cell.nof_prb; i++) {
pilots[SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i,l,cell) + (2*cell.nof_prb)] = sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)];
fidx += SRSLTE_NRE/6;
}
}
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}

@ -152,7 +152,7 @@ int main(int argc, char **argv) {
bzero(h, sizeof(cf_t) * num_re);
srslte_refsignal_cs_put_sf(cell, n_port,
est.csr_signal.pilots[n_port/2][sf_idx], input);
est.csr_refs.pilots[n_port/2][sf_idx], input);
for (i=0;i<2*SRSLTE_CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * SRSLTE_NRE;j++) {

@ -37,7 +37,13 @@
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir) {
return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, dir, SRSLTE_SF_NORM);
}
int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir, srslte_sf_t sf_type) {
if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) {
fprintf(stderr, "Error: Creating DFT plan\n");
@ -60,6 +66,7 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p
q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = SRSLTE_CP_NSYMB(cp);
q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT);
q->cp = cp;
q->freq_shift = false;
q->nof_re = nof_prb * SRSLTE_NRE;
@ -70,9 +77,19 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p
dir==SRSLTE_DFT_FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols,
q->cp==SRSLTE_CP_NORM?"Normal":"Extended", q->nof_re, q->nof_guards);
// MBSFN logic
if (sf_type == SRSLTE_SF_MBSFN) {
q->mbsfn_subframe = true;
q->non_mbsfn_region = 2; // default set to 2
}
return SRSLTE_SUCCESS;
}
void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q, uint8_t non_mbsfn_region)
{
q->non_mbsfn_region = non_mbsfn_region;
}
int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb) {
@ -120,6 +137,17 @@ int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) {
return srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_FORWARD);
}
int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb)
{
int symbol_sz = srslte_symbol_sz(nof_prb);
if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN);
}
int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) {
uint32_t i;
int ret;
@ -130,9 +158,34 @@ int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) {
return -1;
}
q->max_prb = max_prb;
ret = srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD);
if (ret == SRSLTE_SUCCESS) {
srslte_dft_plan_set_norm(&q->fft_plan, false);
/* set now zeros at CP */
for (i=0;i<q->nof_symbols;i++) {
bzero(q->tmp, q->nof_guards * sizeof(cf_t));
bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t));
}
}
return ret;
}
int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb)
{
uint32_t i;
int ret;
int symbol_sz = srslte_symbol_sz(nof_prb);
if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
ret = srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN);
if (ret == SRSLTE_SUCCESS) {
srslte_dft_plan_set_norm(&q->fft_plan, false);
@ -190,7 +243,6 @@ int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) {
void srslte_ofdm_rx_free(srslte_ofdm_t *q) {
srslte_ofdm_free_(q);
}
/* Shifts the signal after the iFFT or before the FFT.
* Freq_shift is relative to inter-carrier spacing.
* Caution: This function shall not be called during run-time
@ -233,6 +285,23 @@ void srslte_ofdm_rx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
}
}
void srslte_ofdm_rx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output)
{
uint32_t i;
for(i = 0; i < q->nof_symbols_mbsfn; i++){
if(i == q->non_mbsfn_region) {
input += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region,q->symbol_sz);
}
input += (i>=q->non_mbsfn_region)?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz);
srslte_dft_run_c(&q->fft_plan, input, q->tmp);
memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t));
input += q->symbol_sz;
output += q->nof_re;
}
}
void srslte_ofdm_rx_slot_zerocopy(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
uint32_t i;
for (i=0;i<q->nof_symbols;i++) {
@ -250,9 +319,15 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
if (q->freq_shift) {
srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz);
}
if(!q->mbsfn_subframe){
for (n=0;n<2;n++) {
srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]);
}
}
else{
srslte_ofdm_rx_slot_mbsfn(q, &input[0*q->slot_sz], &output[0*q->nof_re*q->nof_symbols]);
srslte_ofdm_rx_slot(q, &input[1*q->slot_sz], &output[1*q->nof_re*q->nof_symbols]);
}
}
/* Transforms input OFDM symbols into output samples.
@ -271,16 +346,43 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
}
}
void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output)
{
uint32_t i, cp_len;
for(i=0;i<q->nof_symbols_mbsfn;i++) {
cp_len = ( i>(q->non_mbsfn_region-1) )?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));
srslte_dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]);
input += q->nof_re;
/* add CP */
memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t));
output += q->symbol_sz + cp_len;
/*skip the small section between the non mbms region and the mbms region*/
if(i == (q->non_mbsfn_region - 1))
output += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region,q->symbol_sz);
}
}
void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable) {
srslte_dft_plan_set_norm(&q->fft_plan, normalize_enable);
}
void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output)
{
uint32_t n;
if(!q->mbsfn_subframe){
for (n=0;n<2;n++) {
srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]);
}
}
else{
srslte_ofdm_tx_slot_mbsfn(q, &input[0*q->nof_re*q->nof_symbols], &output[0*q->slot_sz]);
srslte_ofdm_tx_slot(q, &input[1*q->nof_re*q->nof_symbols], &output[1*q->slot_sz]);
}
if (q->freq_shift) {
srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz);
}
}

@ -122,7 +122,7 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q)
srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch);
srslte_refsignal_cs_free(&q->csr_signal);
srslte_refsignal_free(&q->csr_signal);
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
if (q->sf_symbols[i]) {

@ -0,0 +1,486 @@
/**
*
* \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/.
*
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#include "prb_dl.h"
#include "srslte/phy/phch/sch.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#define MAX_PMCH_RE (2 * SRSLTE_CP_EXT_NSYMB * 12)
const static srslte_mod_t modulations[4] =
{ SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM };
//#define DEBUG_IDX
#ifdef DEBUG_IDX
cf_t *offset_original=NULL;
extern int indices[100000];
extern int indices_ptr;
#endif
float srslte_pmch_coderate(uint32_t tbs, uint32_t nof_re)
{
return (float) (tbs + 24)/(nof_re);
}
int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put)
{
uint32_t s, n, l, lp, lstart, lend, nof_refs;
cf_t *in_ptr = input, *out_ptr = output;
uint32_t offset = 0;
#ifdef DEBUG_IDX
indices_ptr = 0;
if (put) {
offset_original = output;
} else {
offset_original = input;
}
#endif
nof_refs = 6;
for (s = 0; s < 2; s++) {
for (l = 0; l < SRSLTE_CP_EXT_NSYMB; l++) {
for (n = 0; n < q->cell.nof_prb; n++) {
// If this PRB is assigned
if (true) {
if (s == 0) {
lstart = lstart_grant;
} else {
lstart = 0;
}
lend = SRSLTE_CP_EXT_NSYMB;
lp = l + s * SRSLTE_CP_EXT_NSYMB;
if (put) {
out_ptr = &output[(lp * q->cell.nof_prb + n) * SRSLTE_NRE];
} else {
in_ptr = &input[(lp * q->cell.nof_prb + n) * SRSLTE_NRE];
}
// This is a symbol in a normal PRB with or without references
if (l >= lstart && l < lend) {
if (SRSLTE_SYMBOL_HAS_REF_MBSFN(l,s)) {
if (l == 0 && s == 1) {
offset = 1;
} else {
offset = 0;
}
prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs, put);
} else {
prb_cp(&in_ptr, &out_ptr, 1);
}
}
}
}
}
}
int r;
if (put) {
r = abs((int) (input - in_ptr));
} else {
r = abs((int) (output - out_ptr));
}
return r;
}
/**
* Puts PMCH in slot number 1
*
* Returns the number of symbols written to sf_symbols
*
* 36.211 10.3 section 6.3.5
*/
int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart)
{
return srslte_pmch_cp(q, symbols, sf_symbols, lstart, true);
}
/**
* Extracts PMCH from slot number 1
*
* Returns the number of symbols written to PMCH
*
* 36.211 10.3 section 6.3.5
*/
int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart)
{
return srslte_pmch_cp(q, sf_symbols, symbols, lstart, false);
}
int srslte_pmch_init(srslte_pmch_t *q, uint32_t max_prb)
{
return srslte_pmch_init_multi(q, max_prb, 1);
}
int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
int i;
if (q != NULL &&
nof_rx_antennas <= SRSLTE_MAX_PORTS)
{
bzero(q, sizeof(srslte_pmch_t));
ret = SRSLTE_ERROR;
q->cell.nof_prb = max_prb;
q->cell.nof_ports = 1;
q->max_re = max_prb * MAX_PMCH_RE;
q->nof_rx_antennas = nof_rx_antennas;
INFO("Init PMCH: %d PRBs, max_symbols: %d\n",
max_prb, q->max_re);
for (i = 0; i < 4; i++) {
if (srslte_modem_table_lte(&q->mod[i], modulations[i])) {
goto clean;
}
srslte_modem_table_bytes(&q->mod[i]);
}
srslte_sch_init(&q->dl_sch);
// Allocate int16_t for reception (LLRs)
q->e = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->e) {
goto clean;
}
q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->d) {
goto clean;
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->x[i]) {
goto clean;
}
for (int j=0;j<q->nof_rx_antennas;j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->ce[i][j]) {
goto clean;
}
}
}
for (int j=0;j<q->nof_rx_antennas;j++) {
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->symbols[j]) {
goto clean;
}
}
q->seqs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_pmch_seq_t*));
if (!q->seqs) {
perror("calloc");
goto clean;
}
ret = SRSLTE_SUCCESS;
}
clean:
if (ret == SRSLTE_ERROR) {
srslte_pmch_free(q);
}
return ret;
}
void srslte_pmch_free(srslte_pmch_t *q) {
uint16_t i;
if (q->e) {
free(q->e);
}
if (q->d) {
free(q->d);
}
for (i = 0; i < q->cell.nof_ports; i++) {
if (q->x[i]) {
free(q->x[i]);
}
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
}
for (i=0;i<q->nof_rx_antennas;i++) {
if (q->symbols[i]) {
free(q->symbols[i]);
}
}
if (q->seqs) {
for (i=0; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) {
if (q->seqs[i]) {
srslte_pmch_free_area_id(q, i);
}
}
free(q->seqs);
}
for (i = 0; i < 4; i++) {
srslte_modem_table_free(&q->mod[i]);
}
srslte_sch_free(&q->dl_sch);
bzero(q, sizeof(srslte_pmch_t));
}
/* Precalculate the scramble sequences for a given MBSFN area ID. This function takes a while
* to execute.
*/
int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id) {
uint32_t i;
if (!q->seqs[area_id]) {
q->seqs[area_id] = calloc(1, sizeof(srslte_pmch_seq_t));
if (q->seqs[area_id]) {
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
if (srslte_sequence_pmch(&q->seqs[area_id]->seq[i], 2 * i , area_id, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
return SRSLTE_ERROR;
}
}
}
}
return SRSLTE_SUCCESS;
}
void srslte_pmch_free_area_id(srslte_pmch_t* q, uint16_t area_id)
{
if (q->seqs[area_id]) {
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
srslte_sequence_free(&q->seqs[area_id]->seq[i]);
}
free(q->seqs[area_id]);
q->seqs[area_id] = NULL;
}
}
int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx)
{
if (cfg) {
if (grant) {
memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t));
}
if (srslte_cbsegm(&cfg->cb_segm[0], cfg->grant.mcs[0].tbs)) {
fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs[0].tbs);
return SRSLTE_ERROR;
}
srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits);
cfg->sf_idx = sf_idx;
cfg->rv[0] = SRSLTE_PMCH_RV;
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
int srslte_pmch_decode(srslte_pmch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint16_t area_id, uint8_t *data)
{
cf_t *_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
_sf_symbols[0] = sf_symbols;
for (int i=0;i<q->cell.nof_ports;i++) {
_ce[i][0] = ce[i];
}
return srslte_pmch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, area_id, data);
}
/** Decodes the pmch from the received symbols
*/
int srslte_pmch_decode_multi(srslte_pmch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate,
uint16_t area_id, uint8_t *data)
{
/* Set pointers for layermapping & precoding */
uint32_t i, n;
cf_t *x[SRSLTE_MAX_LAYERS];
if (q != NULL &&
sf_symbols != NULL &&
data != NULL &&
cfg != NULL)
{
INFO("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n",
cfg->sf_idx, area_id, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, cfg->nbits[0].nof_re,
cfg->nbits[0].nof_bits, 0, cfg->grant.nof_prb, cfg->nbits[0].lstart-1);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
for (int j=0;j<q->nof_rx_antennas;j++) {
/* extract symbols */
n = srslte_pmch_get(q, sf_symbols[j], q->symbols[j], cfg->nbits[0].lstart);
if (n != cfg->nbits[0].nof_re) {
fprintf(stderr, "PMCH 1 extract symbols error expecting %d symbols but got %d, lstart %d\n", cfg->nbits[0].nof_re, n, cfg->nbits[0].lstart);
return SRSLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = srslte_pmch_get(q, ce[i][j], q->ce[i][j], cfg->nbits[0].lstart);
if (n != cfg->nbits[0].nof_re) {
fprintf(stderr, "PMCH 2 extract chest error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n);
return SRSLTE_ERROR;
}
}
}
// No tx diversity in MBSFN
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, noise_estimate);
if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0);
srslte_vec_save_file("subframe.dat", sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
DEBUG("SAVED FILE hest0.dat: channel estimates for port 4\n",0);
srslte_vec_save_file("hest0.dat", ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
DEBUG("SAVED FILE pmch_symbols.dat: symbols after equalization\n",0);
srslte_vec_save_file("pmch_symbols.bin", q->d, cfg->nbits[0].nof_re*sizeof(cf_t));
}
/* 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 thde LLRs normalization
*/
srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re);
/* descramble */
srslte_scrambling_s_offset(&q->seqs[area_id]->seq[cfg->sf_idx], q->e, 0, cfg->nbits[0].nof_bits);
if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0);
srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t));
}
return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
int srslte_pmch_encode(srslte_pmch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
uint8_t *data, uint16_t area_id, cf_t *sf_symbols[SRSLTE_MAX_PORTS])
{
int i;
/* Set pointers for layermapping & precoding */
cf_t *x[SRSLTE_MAX_LAYERS];
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && cfg != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {
if (sf_symbols[i] == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
if (cfg->grant.mcs[0].tbs == 0) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (cfg->nbits[0].nof_re > q->max_re) {
fprintf(stderr,
"Error too many RE per subframe (%d). PMCH configured for %d RE (%d PRB)\n",
cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb);
return SRSLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PMCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs,
cfg->nbits[0].nof_re, cfg->nbits[0].nof_bits, 0);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
// TODO: use tb_encode directly
if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e)) {
fprintf(stderr, "Error encoding TB\n");
return SRSLTE_ERROR;
}
/* scramble */
srslte_scrambling_bytes(&q->seqs[area_id]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits[0].nof_bits);
srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs[0].mod], (uint8_t*) q->e, q->d, cfg->nbits[0].nof_bits);
/* No tx diversity in MBSFN */
memcpy(q->symbols[0], q->d, cfg->nbits[0].nof_re * sizeof(cf_t));
/* mapping to resource elements */
for (i = 0; i < q->cell.nof_ports; i++) {
srslte_pmch_put(q, q->symbols[i], sf_symbols[i], cfg->nbits[0].lstart);
}
ret = SRSLTE_SUCCESS;
}
return ret;
}
float srslte_pmch_average_noi(srslte_pmch_t *q)
{
return q->dl_sch.average_nof_iterations;
}
uint32_t srslte_pmch_last_noi(srslte_pmch_t *q) {
return q->dl_sch.nof_iterations;
}

@ -41,15 +41,19 @@
/* Returns the number of RE in a PRB in a slot and subframe */
uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_t nof_prb,
uint32_t nof_ports, uint32_t nof_ctrl_symbols, srslte_cp_t cp) {
uint32_t nof_ports, uint32_t nof_ctrl_symbols, srslte_cp_t cp, srslte_sf_t sf_type) {
uint32_t re;
bool skip_refs = false;
bool skip_refs = true;
srslte_cp_t cp_ = cp;
if(SRSLTE_SF_MBSFN == sf_type) {
cp_ = SRSLTE_CP_EXT;
}
if (slot == 0) {
re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols) * SRSLTE_NRE;
re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols) * SRSLTE_NRE;
} else {
re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE;
re = SRSLTE_CP_NSYMB(cp_) * SRSLTE_NRE;
}
/* if it's the prb in the middle, there are less RE due to PBCH and PSS/SSS */
@ -57,18 +61,18 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_
&& (prb_idx >= nof_prb / 2 - 3 && prb_idx < nof_prb / 2 + 3 + (nof_prb%2))) {
if (subframe == 0) {
if (slot == 0) {
re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols - 2) * SRSLTE_NRE;
re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE;
} else {
if (SRSLTE_CP_ISEXT(cp)) {
re = (SRSLTE_CP_NSYMB(cp) - 4) * SRSLTE_NRE;
skip_refs = true;
if (SRSLTE_CP_ISEXT(cp_)) {
re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE;
skip_refs = false;
} else {
re = (SRSLTE_CP_NSYMB(cp) - 4) * SRSLTE_NRE + 2 * nof_ports;
re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE + 2 * nof_ports;
}
}
} else if (subframe == 5) {
if (slot == 0) {
re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols - 2) * SRSLTE_NRE;
re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE;
}
}
if ((nof_prb % 2)
@ -77,7 +81,7 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_
re += 2 * SRSLTE_NRE / 2;
} else if (subframe == 0) {
re += 4 * SRSLTE_NRE / 2 - nof_ports;
if (SRSLTE_CP_ISEXT(cp)) {
if (SRSLTE_CP_ISEXT(cp_)) {
re -= nof_ports > 2 ? 2 : nof_ports;
}
}
@ -85,7 +89,8 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_
}
// remove references
if (!skip_refs) {
if (skip_refs) {
if(sf_type == SRSLTE_SF_NORM){
switch (nof_ports) {
case 1:
case 2:
@ -103,6 +108,10 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_
break;
}
}
if(sf_type == SRSLTE_SF_MBSFN){
re -= 6*(slot + 1);
}
}
return re;
}
@ -281,20 +290,20 @@ uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t ce
uint32_t sf_idx, uint32_t nof_ctrl_symbols)
{
uint32_t j, s;
// Compute number of RE per PRB
uint32_t nof_re = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < cell.nof_prb; j++) {
if (grant->prb_idx[s][j]) {
nof_re += ra_re_x_prb(sf_idx, s, j,
cell.nof_prb, cell.nof_ports, nof_ctrl_symbols, cell.cp);
nof_re += ra_re_x_prb(sf_idx, s, j, cell.nof_prb, cell.nof_ports,
nof_ctrl_symbols, cell.cp, grant->sf_type);
}
}
}
return nof_re;
}
/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213
* Decode dci->type?_alloc to grant
* This function only reads dci->type?_alloc and dci->alloc_type fields.
@ -432,7 +441,7 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_
return SRSLTE_SUCCESS;
}
int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) {
int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) {
uint32_t i_tbs = 0;
int tbs = -1;
if (mcs->idx < 10) {
@ -466,6 +475,52 @@ int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) {
return tbs;
}
int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) {
uint32_t i_tbs = 0;
int tbs = -1;
if (mcs->idx < 5) {
mcs->mod = SRSLTE_MOD_QPSK;
i_tbs = mcs->idx*2;
}else if (mcs->idx < 6) {
mcs->mod = SRSLTE_MOD_16QAM;
i_tbs = mcs->idx*2;
}else if (mcs->idx < 11) {
mcs->mod = SRSLTE_MOD_16QAM;
i_tbs = mcs->idx + 5;
}else if (mcs->idx < 20) {
mcs->mod = SRSLTE_MOD_64QAM;
i_tbs = mcs->idx + 5;
}else if (mcs->idx < 28) {
//mcs->mod = SRSLTE_MOD_256QAM;
i_tbs = mcs->idx + 5;
}else if (mcs->idx == 28) {
mcs->mod = SRSLTE_MOD_QPSK;
tbs = 0;
i_tbs = 0;
}else if (mcs->idx == 29) {
mcs->mod = SRSLTE_MOD_16QAM;
tbs = 0;
i_tbs = 0;
}else if (mcs->idx == 30) {
mcs->mod = SRSLTE_MOD_64QAM;
tbs = 0;
i_tbs = 0;
}else if (mcs->idx == 31) {
mcs->mod = SRSLTE_MOD_64QAM;
tbs = 0;
i_tbs = 0;
}
if (tbs == -1) {
tbs = srslte_ra_tbs_from_idx(i_tbs, nprb);
if (tbs >= 0) {
mcs->tbs = tbs;
}
}
return tbs;
}
/* Modulation order and transport block size determination 7.1.7 in 36.213
* This looks at DCI type, type of RNTI and reads fields dci->type?_alloc, dci->mcs_idx,
* dci->dci_is_1a and dci->dci_is_1c
@ -496,21 +551,23 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
grant->mcs[0].tbs = (uint32_t) tbs;
} else {
n_prb = grant->nof_prb;
grant->nof_tb = 0;
if (dci->tb_en[0]) {
grant->mcs[0].idx = dci->mcs_idx;
tbs = dl_fill_ra_mcs(&grant->mcs[0], n_prb);
tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb);
if (tbs) {
last_dl_tbs[dci->harq_process%8] = tbs;
} else {
// For mcs>=29, set last TBS received for this PID
grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8];
}
grant->nof_tb++;
} else {
grant->mcs[0].tbs = 0;
}
if (dci->tb_en[1]) {
grant->mcs[1].idx = dci->mcs_idx_1;
tbs = dl_fill_ra_mcs(&grant->mcs[1], n_prb);
tbs = srslte_dl_fill_ra_mcs(&grant->mcs[1], n_prb);
if (tbs) {
last_dl_tbs2[dci->harq_process%8] = tbs;
} else {
@ -545,7 +602,11 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl
/* Compute number of RE for first transport block */
nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi);
nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi;
if (SRSLTE_SF_NORM == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
} else if (SRSLTE_SF_MBSFN == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart;
}
nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i];
}
}
@ -555,6 +616,7 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl
int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci,
uint32_t nof_prb, uint16_t msg_rnti, srslte_ra_dl_grant_t *grant)
{
grant->sf_type = SRSLTE_SF_NORM;
bool crc_is_crnti = false;
if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) {
crc_is_crnti = true;
@ -845,5 +907,3 @@ void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {
}
}

@ -32,10 +32,10 @@
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#include "srslte/phy/phch/pdsch.h"
#include "srslte/phy/phch/pusch.h"
#include "srslte/phy/phch/sch.h"
#include "srslte/phy/phch/pmch.h"
#include "srslte/phy/phch/uci.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/utils/bit.h"

@ -78,3 +78,9 @@ int srslte_sequence_pusch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot,
int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id) {
return srslte_sequence_LTE_pr(seq, 20, ((((nslot/2)+1)*(2*cell_id+1))<<16)+rnti);
}
int srslte_sequence_pmch(srslte_sequence_t *seq, uint32_t nslot, uint32_t mbsfn_id , uint32_t len){
bzero(seq,sizeof(srslte_sequence_t));
return srslte_sequence_LTE_pr(seq, len, (((nslot/2)<<9) + mbsfn_id));
}

@ -65,8 +65,10 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
bzero(q, sizeof(srslte_ue_dl_t));
q->pkt_errors = 0;
q->pkts_total = 0;
q->pdsch_pkt_errors = 0;
q->pdsch_pkts_total = 0;
q->pmch_pkt_errors = 0;
q->pmch_pkts_total = 0;
q->pending_ul_dci_rnti = 0;
q->sample_offset = 0;
q->nof_rx_antennas = nof_rx_antennas;
@ -75,6 +77,13 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
fprintf(stderr, "Error initiating FFT\n");
goto clean_exit;
}
if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, max_prb)) {
fprintf(stderr, "Error initiating FFT for MBSFN subframes \n");
goto clean_exit;
}
srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, 2); // Set a default to init
if (srslte_chest_dl_init(&q->chest, max_prb)) {
fprintf(stderr, "Error initiating channel estimator\n");
goto clean_exit;
@ -97,6 +106,11 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
fprintf(stderr, "Error creating PDSCH object\n");
goto clean_exit;
}
if (srslte_pmch_init_multi(&q->pmch, max_prb, nof_rx_antennas)) {
fprintf(stderr, "Error creating PMCH object\n");
goto clean_exit;
}
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t));
if (!q->softbuffers[i]) {
@ -151,12 +165,14 @@ clean_exit:
void srslte_ue_dl_free(srslte_ue_dl_t *q) {
if (q) {
srslte_ofdm_rx_free(&q->fft);
srslte_ofdm_rx_free(&q->fft_mbsfn);
srslte_chest_dl_free(&q->chest);
srslte_regs_free(&q->regs);
srslte_pcfich_free(&q->pcfich);
srslte_phich_free(&q->phich);
srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch);
srslte_pmch_free(&q->pmch);
srslte_cfo_free(&q->sfo_correct);
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
srslte_softbuffer_rx_free(q->softbuffers[i]);
@ -258,6 +274,34 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) {
q->current_rnti = rnti;
}
/* Set the area ID on pmch and chest_dl to generate scrambling sequence and reference
* signals.
*/
int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q,
uint16_t mbsfn_area_id) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if(q != NULL) {
ret = SRSLTE_ERROR;
if(srslte_chest_dl_set_mbsfn_area_id(&q->chest, mbsfn_area_id)) {
fprintf(stderr, "Error setting MBSFN area ID \n");
return ret;
}
if(srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id)) {
fprintf(stderr, "Error setting MBSFN area ID \n");
return ret;
}
q->current_mbsfn_area_id = mbsfn_area_id;
ret = SRSLTE_SUCCESS;
}
return ret;
}
void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q,
uint8_t non_mbsfn_region_length) {
srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length);
}
void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){
@ -282,17 +326,28 @@ int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_
return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks);
}
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi)
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){
return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM);
}
int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type)
{
if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Run FFT for all subframe data */
for (int j=0;j<q->nof_rx_antennas;j++) {
if(sf_type == SRSLTE_SF_MBSFN ) {
srslte_ofdm_rx_sf(&q->fft_mbsfn, input[j], q->sf_symbols_m[j]);
}else{
srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]);
}
/* Correct SFO multiplying by complex exponential in the time domain */
if (q->sample_offset) {
for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) {
int nsym = (sf_type == SRSLTE_SF_MBSFN)?SRSLTE_CP_EXT_NSYMB:SRSLTE_CP_NSYMB(q->cell.cp);
for (int i=0;i<2*nsym;i++) {
srslte_cfo_correct(&q->sfo_correct,
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
@ -300,18 +355,28 @@ int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_P
}
}
}
return srslte_ue_dl_decode_estimate(q, sf_idx, cfi);
return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, sf_type);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) {
return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM);
}
int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) {
float cfi_corr;
if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Get channel estimates for each port */
if(sf_type == SRSLTE_SF_MBSFN){
srslte_chest_dl_estimate_multi_mbsfn(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas, q->current_mbsfn_area_id);
}else{
srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas);
}
/* First decode PCFICH and obtain CFI */
if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m,
@ -358,7 +423,11 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
}
}
}
if(SRSLTE_SF_MBSFN == grant->sf_type) {
return srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, cfi, sf_idx);
} else {
return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi);
}
}
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
@ -372,7 +441,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
uint32_t cfi;
uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) {
if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) {
return ret;
}
@ -476,12 +545,13 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
noise_estimate,
rnti, data, acks);
for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (grant.tb_en[tb]) {
if (!acks[tb]) {
q->pkt_errors++;
q->pdsch_pkt_errors++;
}
q->pkts_total++;
q->pdsch_pkts_total++;
}
}
@ -510,6 +580,69 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
}
}
int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data,
uint32_t tti)
{
srslte_ra_dl_grant_t grant;
int ret = SRSLTE_ERROR;
uint32_t cfi;
uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) {
return ret;
}
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
// Uncoment next line to do ZF by default in pdsch_ue example
//float noise_estimate = 0;
grant.sf_type = SRSLTE_SF_MBSFN;
grant.nof_tb = 1;
grant.mcs[0].idx = 2;
grant.nof_prb = q->pmch.cell.nof_prb;
srslte_dl_fill_ra_mcs(&grant.mcs[0], grant.nof_prb);
srslte_softbuffer_rx_reset_tbs(q->softbuffers[0], (uint32_t) grant.mcs[0].tbs);
for(int j = 0; j < 2; j++){
for(int f = 0; f < grant.nof_prb; f++){
grant.prb_idx[j][f] = true;
}
}
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
// redundancy version is set to 0 for the PMCH
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) {
return SRSLTE_ERROR;
}
if (q->pmch_cfg.grant.mcs[0].mod > 0 && q->pmch_cfg.grant.mcs[0].tbs >= 0) {
ret = srslte_pmch_decode_multi(&q->pmch, &q->pmch_cfg, q->softbuffers[0],
q->sf_symbols_m, q->ce_m,
noise_estimate,
q->current_mbsfn_area_id, data);
if (ret == SRSLTE_ERROR) {
q->pmch_pkt_errors++;
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling srslte_pmch_decode()\n");
}
}
printf("q->pmch_pkts_total %d \n", q->pmch_pkts_total);
printf("qq->pmch_pkt_errors %d \n", q->pmch_pkt_errors);
q->pmch_pkts_total++;
if (ret == SRSLTE_SUCCESS) {
return q->pmch_cfg.grant.mcs[0].tbs;
} else {
return 0;
}
}
/* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus
* Noise Ratio (SINR), valid for TM4 */
int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, float *current_sinr) {

@ -676,6 +676,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
/* Track PSS/SSS around the expected PSS position
* In tracking phase, the subframe carrying the PSS is always the last one of the frame
*/
switch(srslte_sync_find(&q->strack, input_buffer[0],
q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2,
&track_idx))

Loading…
Cancel
Save