mirror of https://github.com/PentHertz/srsLTE.git
commit
29ca3705a7
|
@ -7,6 +7,7 @@ include(CheckCSourceRuns)
|
|||
option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON)
|
||||
option(ENABLE_AVX "Enable compile-time AVX support." ON)
|
||||
option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON)
|
||||
option(ENABLE_FMA "Enable compile-time FMA support." ON)
|
||||
|
||||
if (ENABLE_SSE)
|
||||
#
|
||||
|
@ -97,8 +98,43 @@ if (ENABLE_SSE)
|
|||
if (HAVE_AVX2)
|
||||
message(STATUS "AVX2 is enabled - target CPU must support it")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_FMA)
|
||||
|
||||
#
|
||||
# Check compiler for AVX intrinsics
|
||||
#
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG )
|
||||
set(CMAKE_REQUIRED_FLAGS "-mfma")
|
||||
check_c_source_runs("
|
||||
#include <immintrin.h>
|
||||
int main()
|
||||
{
|
||||
__m256 a, b, c, r;
|
||||
const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
|
||||
float dst[8];
|
||||
a = _mm256_loadu_ps( src );
|
||||
b = _mm256_loadu_ps( src );
|
||||
c = _mm256_loadu_ps( src );
|
||||
r = _mm256_fmadd_ps( a, b, c );
|
||||
_mm256_storeu_ps( dst, r );
|
||||
int i = 0;
|
||||
for( i = 0; i < 8; i++ ){
|
||||
if( ( src[i] * src[i] + src[i] ) != dst[i] ){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}"
|
||||
HAVE_FMA)
|
||||
endif()
|
||||
|
||||
if (HAVE_FMA)
|
||||
message(STATUS "FMA is enabled - target CPU must support it")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2)
|
||||
mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA)
|
||||
|
|
|
@ -118,7 +118,7 @@ int parse_args(prog_args_t *args, int argc, char **argv) {
|
|||
/**********************************************************************/
|
||||
|
||||
/* TODO: Do something with the output data */
|
||||
uint8_t data[1000000];
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS];
|
||||
|
||||
bool go_exit = false;
|
||||
void sig_int_handler(int signo)
|
||||
|
@ -160,7 +160,8 @@ int main(int argc, char **argv) {
|
|||
int sfn_offset;
|
||||
float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0;
|
||||
cf_t *ce[SRSLTE_MAX_PORTS];
|
||||
float cfo = 0;
|
||||
float cfo = 0;
|
||||
bool acks[SRSLTE_MAX_CODEWORDS] = {false};
|
||||
|
||||
if (parse_args(&prog_args, argc, argv)) {
|
||||
exit(-1);
|
||||
|
@ -183,6 +184,9 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
|
||||
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
data[i] = srslte_vec_malloc(sizeof(uint8_t) * 1500*8);
|
||||
}
|
||||
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
|
@ -241,7 +245,7 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Error initiating ue_sync\n");
|
||||
return -1;
|
||||
}
|
||||
if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) {
|
||||
if (srslte_ue_dl_init(&ue_dl, cell, 1)) {
|
||||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -310,19 +314,19 @@ int main(int argc, char **argv) {
|
|||
case DECODE_SIB:
|
||||
/* We are looking for SI Blocks, search only in appropiate places */
|
||||
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
|
||||
n = srslte_ue_dl_decode_multi(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
|
||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
|
||||
return -1;
|
||||
} else if (n == 0) {
|
||||
printf("CFO: %+6.4f kHz, SFO: %+6.4f kHz, NOI: %.2f, PDCCH-Det: %.3f\r",
|
||||
srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000,
|
||||
srslte_sch_average_noi(&ue_dl.pdsch.dl_sch),
|
||||
srslte_pdsch_average_noi(&ue_dl.pdsch),
|
||||
(float) ue_dl.nof_detected/nof_trials);
|
||||
nof_trials++;
|
||||
} else {
|
||||
printf("Decoded SIB1. Payload: ");
|
||||
srslte_vec_fprint_byte(stdout, data, n/8);;
|
||||
srslte_vec_fprint_byte(stdout, data[0], n/8);;
|
||||
state = MEASURE;
|
||||
}
|
||||
}
|
||||
|
@ -386,6 +390,12 @@ int main(int argc, char **argv) {
|
|||
sf_cnt++;
|
||||
} // Main loop
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
if (data[i]) {
|
||||
free(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
srslte_ue_sync_free(&ue_sync);
|
||||
srslte_rf_close(&rf);
|
||||
printf("\nBye\n");
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
#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>
|
||||
#include <srslte/phy/common/phy_common.h>
|
||||
#include <srslte/phy/phch/pdsch_cfg.h>
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
|
||||
|
@ -55,19 +55,23 @@ char *output_file_name = NULL;
|
|||
#define DOWN_KEY 66
|
||||
|
||||
srslte_cell_t cell = {
|
||||
25, // nof_prb
|
||||
1, // nof_ports
|
||||
0, // cell_id
|
||||
SRSLTE_CP_NORM, // cyclic prefix
|
||||
SRSLTE_PHICH_R_1, // PHICH resources
|
||||
SRSLTE_PHICH_NORM // PHICH length
|
||||
25, // nof_prb
|
||||
1, // nof_ports
|
||||
0, // cell_id
|
||||
SRSLTE_CP_NORM, // cyclic prefix
|
||||
SRSLTE_PHICH_NORM, // PHICH length
|
||||
SRSLTE_PHICH_R_1 // PHICH resources
|
||||
};
|
||||
|
||||
|
||||
int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device
|
||||
|
||||
uint32_t cfi=3;
|
||||
uint32_t cfi = 1;
|
||||
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;
|
||||
|
||||
char *rf_args = "";
|
||||
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
|
||||
|
@ -80,14 +84,15 @@ srslte_pcfich_t pcfich;
|
|||
srslte_pdcch_t pdcch;
|
||||
srslte_pdsch_t pdsch;
|
||||
srslte_pdsch_cfg_t pdsch_cfg;
|
||||
srslte_softbuffer_tx_t softbuffer;
|
||||
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
|
||||
srslte_regs_t regs;
|
||||
srslte_ra_dl_dci_t ra_dl;
|
||||
srslte_ra_dl_dci_t ra_dl;
|
||||
int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0};
|
||||
|
||||
cf_t *sf_buffer = NULL, *output_buffer = NULL;
|
||||
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;
|
||||
pthread_t net_thread;
|
||||
void *net_thread_fnc(void *arg);
|
||||
sem_t net_sem;
|
||||
bool net_packet_ready = false;
|
||||
|
@ -97,9 +102,12 @@ srslte_netsink_t net_sink;
|
|||
int prbset_num = 1, last_prbset_num = 1;
|
||||
int prbset_orig = 0;
|
||||
|
||||
#define DATA_BUFF_SZ 1024*1024
|
||||
uint8_t *data[2], data2[DATA_BUFF_SZ];
|
||||
uint8_t data_tmp[DATA_BUFF_SZ];
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agmfoncvpu]\n", prog);
|
||||
printf("Usage: %s [agmfoncvpuxb]\n", prog);
|
||||
#ifndef DISABLE_RF
|
||||
printf("\t-a RF args [Default %s]\n", rf_args);
|
||||
printf("\t-l RF amplitude [Default %.2f]\n", rf_amp);
|
||||
|
@ -113,13 +121,18 @@ 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-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);
|
||||
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port);
|
||||
printf("\t-v [set srslte_verbose to debug, default none]\n");
|
||||
printf("\n");
|
||||
printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "aglfmoncpvu")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
rf_args = argv[optind];
|
||||
|
@ -151,6 +164,15 @@ void parse_args(int argc, char **argv) {
|
|||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'x':
|
||||
strncpy(mimo_type_str, argv[optind], 32);
|
||||
break;
|
||||
case 'b':
|
||||
multiplex_pmi = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'w':
|
||||
multiplex_nof_layers = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
|
@ -168,18 +190,61 @@ void parse_args(int argc, char **argv) {
|
|||
}
|
||||
|
||||
void base_init() {
|
||||
|
||||
int i;
|
||||
|
||||
/* Select transmission mode */
|
||||
if (srslte_str2mimotype(mimo_type_str, &pdsch_cfg.mimo_type)) {
|
||||
ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd and multiplex");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Configure cell and PDSCH in function of the transmission mode */
|
||||
switch(pdsch_cfg.mimo_type) {
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
cell.nof_ports = 1;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
cell.nof_ports = 2;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
cell.nof_ports = 2;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
cell.nof_ports = 2;
|
||||
break;
|
||||
default:
|
||||
ERROR("Transmission mode not implemented.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Allocate memory */
|
||||
for(i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
data[i] = srslte_vec_malloc(sizeof(uint8_t) * SOFTBUFFER_SIZE);
|
||||
if (!data[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
bzero(data[i], sizeof(uint8_t) * SOFTBUFFER_SIZE);
|
||||
}
|
||||
|
||||
/* init memory */
|
||||
sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
if (!sf_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
sf_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
if (!sf_buffer[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
if (!output_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
output_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
|
||||
if (!output_buffer[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples);
|
||||
}
|
||||
|
||||
/* open file or USRP */
|
||||
if (output_file_name) {
|
||||
if (strcmp(output_file_name, "NULL")) {
|
||||
|
@ -194,7 +259,7 @@ void base_init() {
|
|||
} else {
|
||||
#ifndef DISABLE_RF
|
||||
printf("Opening RF device...\n");
|
||||
if (srslte_rf_open(&rf, rf_args)) {
|
||||
if (srslte_rf_open_multi(&rf, rf_args, cell.nof_ports)) {
|
||||
fprintf(stderr, "Error opening rf\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -247,27 +312,41 @@ void base_init() {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (srslte_pdcch_init(&pdcch, ®s, cell)) {
|
||||
if (srslte_pdcch_init_tx(&pdcch, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (srslte_pdsch_init(&pdsch, cell)) {
|
||||
bzero(&pdsch, sizeof(srslte_pdsch_t));
|
||||
if (srslte_pdsch_init_tx(&pdsch, cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
srslte_pdsch_set_rnti(&pdsch, UE_CRNTI);
|
||||
|
||||
if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating soft buffer\n");
|
||||
exit(-1);
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
|
||||
if (!softbuffers[i]) {
|
||||
fprintf(stderr, "Error allocating soft buffer\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (srslte_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating soft buffer\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
srslte_softbuffer_tx_free(&softbuffer);
|
||||
int i;
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
srslte_softbuffer_tx_free(softbuffers[i]);
|
||||
if (softbuffers[i]) {
|
||||
free(softbuffers[i]);
|
||||
}
|
||||
}
|
||||
srslte_pdsch_free(&pdsch);
|
||||
srslte_pdcch_free(&pdcch);
|
||||
srslte_regs_free(®s);
|
||||
|
@ -275,11 +354,20 @@ void base_free() {
|
|||
|
||||
srslte_ofdm_tx_free(&ifft);
|
||||
|
||||
if (sf_buffer) {
|
||||
free(sf_buffer);
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
if (data[i]) {
|
||||
free(data[i]);
|
||||
}
|
||||
}
|
||||
if (output_buffer) {
|
||||
free(output_buffer);
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
if (sf_buffer[i]) {
|
||||
free(sf_buffer[i]);
|
||||
}
|
||||
|
||||
if (output_buffer[i]) {
|
||||
free(output_buffer[i]);
|
||||
}
|
||||
}
|
||||
if (output_file_name) {
|
||||
if (!null_file_sink) {
|
||||
|
@ -332,15 +420,45 @@ uint32_t prbset_to_bitmask() {
|
|||
}
|
||||
|
||||
int update_radl() {
|
||||
|
||||
|
||||
/* Configure cell and PDSCH in function of the transmission mode */
|
||||
switch(pdsch_cfg.mimo_type) {
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
pdsch_cfg.nof_layers = 1;
|
||||
nof_tb = 1;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
pdsch_cfg.nof_layers = 2;
|
||||
nof_tb = 1;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
pdsch_cfg.nof_layers = 2;
|
||||
nof_tb = 2;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
pdsch_cfg.nof_layers = multiplex_nof_layers;
|
||||
nof_tb = multiplex_nof_layers;
|
||||
break;
|
||||
default:
|
||||
ERROR("Transmission mode not implemented.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
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.rv_idx = rvidx[0];
|
||||
ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
|
||||
ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask();
|
||||
ra_dl.tb_en[0] = 1;
|
||||
ra_dl.tb_en[0] = 1;
|
||||
|
||||
if (nof_tb > 1) {
|
||||
ra_dl.mcs_idx_1 = mcs_idx;
|
||||
ra_dl.ndi_1 = 0;
|
||||
ra_dl.rv_idx_1 = rvidx[1];
|
||||
ra_dl.tb_en[1] = 1;
|
||||
}
|
||||
|
||||
srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
|
||||
srslte_ra_dl_grant_t dummy_grant;
|
||||
|
@ -348,8 +466,21 @@ 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);
|
||||
printf("Type new MCS index and press Enter: "); fflush(stdout);
|
||||
|
||||
|
||||
if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) {
|
||||
printf("\nTransmission mode key table:\n");
|
||||
printf(" Mode | 1TB | 2TB |\n");
|
||||
printf("----------+---------+-----+\n");
|
||||
printf("Diversity | x | |\n");
|
||||
printf(" CDD | | z |\n");
|
||||
printf("Multiplex | q,w,e,r | a,s |\n");
|
||||
printf("\n");
|
||||
printf("Type new MCS index (0-28) or mode key and press Enter: ");
|
||||
} else {
|
||||
printf("Type new MCS index (0-28) and press Enter: ");
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -390,8 +521,47 @@ int update_control() {
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
last_mcs_idx = mcs_idx;
|
||||
mcs_idx = atoi(input);
|
||||
switch (input[0]) {
|
||||
case 'q':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
multiplex_pmi = 0;
|
||||
multiplex_nof_layers = 1;
|
||||
break;
|
||||
case 'w':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
multiplex_pmi = 1;
|
||||
multiplex_nof_layers = 1;
|
||||
break;
|
||||
case 'e':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
multiplex_pmi = 2;
|
||||
multiplex_nof_layers = 1;
|
||||
break;
|
||||
case 'r':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
multiplex_pmi = 3;
|
||||
multiplex_nof_layers = 1;
|
||||
break;
|
||||
case 'a':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
multiplex_pmi = 0;
|
||||
multiplex_nof_layers = 2;
|
||||
break;
|
||||
case 's':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
multiplex_pmi = 1;
|
||||
multiplex_nof_layers = 2;
|
||||
break;
|
||||
case 'z':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD;
|
||||
break;
|
||||
case 'x':
|
||||
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
break;
|
||||
default:
|
||||
last_mcs_idx = mcs_idx;
|
||||
mcs_idx = atoi(input);
|
||||
}
|
||||
}
|
||||
bzero(input,sizeof(input));
|
||||
if (update_radl()) {
|
||||
|
@ -411,10 +581,6 @@ int update_control() {
|
|||
}
|
||||
}
|
||||
|
||||
#define DATA_BUFF_SZ 1024*128
|
||||
uint8_t data[8*DATA_BUFF_SZ], data2[DATA_BUFF_SZ];
|
||||
uint8_t data_tmp[DATA_BUFF_SZ];
|
||||
|
||||
/** Function run in a separate thread to receive UDP data */
|
||||
void *net_thread_fnc(void *arg) {
|
||||
int n;
|
||||
|
@ -423,14 +589,16 @@ void *net_thread_fnc(void *arg) {
|
|||
do {
|
||||
n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm);
|
||||
if (n > 0) {
|
||||
int nbytes = 1+(pdsch_cfg.grant.mcs.tbs-1)/8;
|
||||
// FIXME: I assume that both transport blocks have same size in case of 2 tb are active
|
||||
int nbytes = 1 + (pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs - 1) / 8;
|
||||
rpm += n;
|
||||
INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes);
|
||||
wpm = 0;
|
||||
while (rpm >= nbytes) {
|
||||
// wait for packet to be transmitted
|
||||
sem_wait(&net_sem);
|
||||
memcpy(data, &data2[wpm], nbytes);
|
||||
memcpy(data[0], &data2[wpm], nbytes / (size_t) 2);
|
||||
memcpy(data[1], &data2[wpm], nbytes / (size_t) 2);
|
||||
INFO("Sent %d/%d bytes ready\n", nbytes, rpm);
|
||||
rpm -= nbytes;
|
||||
wpm += nbytes;
|
||||
|
@ -497,9 +665,9 @@ int main(int argc, char **argv) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_PORTS; i++) { // now there's only 1 port
|
||||
sf_symbols[i] = sf_buffer;
|
||||
slot1_symbols[i] = &sf_buffer[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
|
||||
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
|
||||
|
@ -556,7 +724,9 @@ int main(int argc, char **argv) {
|
|||
nf = 0;
|
||||
|
||||
bool send_data = false;
|
||||
srslte_softbuffer_tx_reset(&softbuffer);
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
srslte_softbuffer_tx_reset(softbuffers[i]);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_RF
|
||||
bool start_of_burst = true;
|
||||
|
@ -564,15 +734,25 @@ int main(int argc, char **argv) {
|
|||
|
||||
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);
|
||||
/* 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_buffer, cell.nof_prb, SRSLTE_CP_NORM);
|
||||
srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
|
||||
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,
|
||||
SRSLTE_CP_NORM);
|
||||
}
|
||||
|
||||
srslte_refsignal_cs_put_sf(cell, 0, est.csr_signal.pilots[0][sf_idx], sf_buffer);
|
||||
/* Copy zeros, SSS, PSS into the rest of antenna ports */
|
||||
for (i = 1; i < cell.nof_ports; i++) {
|
||||
memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re);
|
||||
}
|
||||
|
||||
/* Put reference signals */
|
||||
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_pbch_mib_pack(&cell, sfn, bch_payload);
|
||||
if (sf_idx == 0) {
|
||||
|
@ -593,9 +773,11 @@ int main(int argc, char **argv) {
|
|||
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;
|
||||
INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs);
|
||||
for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; tb++) {
|
||||
for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) {
|
||||
data[tb][i] = (uint8_t) rand();
|
||||
}
|
||||
}
|
||||
/* Uncomment this to transmit on sf 0 and 5 only */
|
||||
if (sf_idx != 0 && sf_idx != 5) {
|
||||
|
@ -606,10 +788,30 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (send_data) {
|
||||
|
||||
srslte_dci_format_t dci_format;
|
||||
switch(pdsch_cfg.mimo_type) {
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
dci_format = SRSLTE_DCI_FORMAT1;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
dci_format = SRSLTE_DCI_FORMAT2A;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
dci_format = SRSLTE_DCI_FORMAT2;
|
||||
if (multiplex_nof_layers == 1) {
|
||||
ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1);
|
||||
} else {
|
||||
ra_dl.pinfo = (uint8_t) multiplex_pmi;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Wrong MIMO configuration\n");
|
||||
exit(SRSLTE_ERROR);
|
||||
}
|
||||
/* 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);
|
||||
srslte_dci_msg_pack_pdsch(&ra_dl, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false);
|
||||
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);
|
||||
|
@ -618,22 +820,24 @@ int main(int argc, char **argv) {
|
|||
/* Configure pdsch_cfg parameters */
|
||||
srslte_ra_dl_grant_t grant;
|
||||
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant);
|
||||
if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0)) {
|
||||
if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) {
|
||||
fprintf(stderr, "Error configuring PDSCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Encode PDSCH */
|
||||
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer, data, UE_CRNTI, sf_symbols)) {
|
||||
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, 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");
|
||||
}
|
||||
for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; 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);
|
||||
|
@ -641,21 +845,24 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
/* Transform to OFDM symbols */
|
||||
srslte_ofdm_tx_sf(&ifft, sf_buffer, output_buffer);
|
||||
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]);
|
||||
}
|
||||
|
||||
/* send to file or usrp */
|
||||
if (output_file_name) {
|
||||
if (!null_file_sink) {
|
||||
srslte_filesink_write(&fsink, output_buffer, sf_n_samples);
|
||||
srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports);
|
||||
}
|
||||
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;
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
}
|
||||
srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false);
|
||||
start_of_burst=false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
#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/srslte.h"
|
||||
|
||||
|
@ -98,6 +101,7 @@ typedef struct {
|
|||
int net_port_signal;
|
||||
char *net_address_signal;
|
||||
int decimate;
|
||||
int verbose;
|
||||
}prog_args_t;
|
||||
|
||||
void args_default(prog_args_t *args) {
|
||||
|
@ -238,6 +242,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
|
|||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
args->verbose = srslte_verbose;
|
||||
break;
|
||||
case 'Z':
|
||||
args->decimate = atoi(argv[optind]);
|
||||
|
@ -258,7 +263,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
|
|||
/**********************************************************************/
|
||||
|
||||
/* TODO: Do something with the output data */
|
||||
uint8_t data[20000];
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS];
|
||||
|
||||
bool go_exit = false;
|
||||
void sig_int_handler(int signo)
|
||||
|
@ -266,10 +271,12 @@ void sig_int_handler(int signo)
|
|||
printf("SIGINT received. Exiting...\n");
|
||||
if (signo == SIGINT) {
|
||||
go_exit = true;
|
||||
} else if (signo == SIGSEGV) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
cf_t *sf_buffer[2] = {NULL, NULL};
|
||||
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) {
|
||||
|
@ -298,6 +305,12 @@ 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
|
||||
#define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
int decimate = 1;
|
||||
|
@ -308,13 +321,20 @@ int main(int argc, char **argv) {
|
|||
srslte_rf_t rf;
|
||||
#endif
|
||||
uint32_t nof_trials = 0;
|
||||
int n;
|
||||
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
|
||||
int sfn_offset;
|
||||
float cfo = 0;
|
||||
|
||||
|
||||
parse_args(&prog_args, argc, argv);
|
||||
|
||||
for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) {
|
||||
data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8);
|
||||
if (!data[i]) {
|
||||
ERROR("Allocating data");
|
||||
go_exit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(prog_args.cpu_affinity > -1) {
|
||||
|
||||
cpu_set_t cpuset;
|
||||
|
@ -379,8 +399,8 @@ int main(int argc, char **argv) {
|
|||
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
|
||||
|
||||
/* set receiver frequency */
|
||||
printf("Tunning receiver to %.3f MHz\n", prog_args.rf_freq/1000000);
|
||||
srslte_rf_set_rx_freq(&rf, prog_args.rf_freq);
|
||||
printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq)/1000000);
|
||||
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;
|
||||
|
@ -435,8 +455,8 @@ int main(int argc, char **argv) {
|
|||
cell.nof_ports = prog_args.file_nof_ports;
|
||||
cell.nof_prb = prog_args.file_nof_prb;
|
||||
|
||||
if (srslte_ue_sync_init_file(&ue_sync, prog_args.file_nof_prb,
|
||||
prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq)) {
|
||||
if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb,
|
||||
prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq, prog_args.rf_nof_rx_ant)) {
|
||||
fprintf(stderr, "Error initiating ue_sync\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -467,7 +487,7 @@ int main(int argc, char **argv) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_init_multi(&ue_dl, cell, prog_args.rf_nof_rx_ant)) { // This is the User RNTI
|
||||
if (srslte_ue_dl_init(&ue_dl, cell, prog_args.rf_nof_rx_ant)) { // This is the User RNTI
|
||||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -498,9 +518,15 @@ int main(int argc, char **argv) {
|
|||
|
||||
// Variables for measurements
|
||||
uint32_t nframes=0;
|
||||
float rsrp=0.0, rsrq=0.0, noise=0.0;
|
||||
uint32_t ri = 0, pmi = 0;
|
||||
float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0,
|
||||
sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0;
|
||||
bool decode_pdsch = false;
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_LAYERS; i++) {
|
||||
bzero(sinr[i], sizeof(float)*SRSLTE_MAX_CODEBOOKS);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_RF
|
||||
if (prog_args.rf_gain < 0) {
|
||||
srslte_ue_sync_start_agc(&ue_sync, srslte_rf_set_rx_gain_th_wrapper_, cell_detect_config.init_agc);
|
||||
|
@ -521,7 +547,29 @@ int main(int argc, char **argv) {
|
|||
INFO("\nEntering main loop...\n\n", 0);
|
||||
/* Main loop */
|
||||
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
|
||||
|
||||
bool acks [SRSLTE_MAX_CODEWORDS] = {false};
|
||||
char input[128];
|
||||
PRINT_LINE_INIT();
|
||||
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(0, &set);
|
||||
|
||||
struct timeval to;
|
||||
to.tv_sec = 0;
|
||||
to.tv_usec = 0;
|
||||
|
||||
/* Set default verbose level */
|
||||
srslte_verbose = prog_args.verbose;
|
||||
int n = select(1, &set, NULL, NULL, &to);
|
||||
if (n == 1) {
|
||||
/* If a new line is detected set verbose level to Debug */
|
||||
if (fgets(input, sizeof(input), stdin)) {
|
||||
srslte_verbose = SRSLTE_VERBOSE_DEBUG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
|
||||
|
@ -561,12 +609,30 @@ int main(int argc, char **argv) {
|
|||
decode_pdsch = false;
|
||||
}
|
||||
}
|
||||
if (decode_pdsch) {
|
||||
INFO("Attempting DL decode SFN=%d\n", sfn);
|
||||
n = srslte_ue_dl_decode_multi(&ue_dl,
|
||||
sf_buffer,
|
||||
data,
|
||||
sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
|
||||
|
||||
INFO("Attempting DL decode SFN=%d\n", sfn);
|
||||
if (decode_pdsch) {
|
||||
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);
|
||||
} else {
|
||||
if (prog_args.rf_nof_rx_ant == 1) {
|
||||
/* Transmission mode 2 */
|
||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
||||
acks);
|
||||
} else {
|
||||
/* Transmission mode 3 */
|
||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
||||
acks);
|
||||
if (n < 1) {
|
||||
/* Transmission mode 4 */
|
||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
||||
acks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (n < 0) {
|
||||
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
|
||||
|
@ -574,7 +640,11 @@ int main(int argc, char **argv) {
|
|||
|
||||
/* Send data if socket active */
|
||||
if (prog_args.net_port > 0) {
|
||||
srslte_netsink_write(&net_sink, data, 1+(n-1)/8);
|
||||
// FIXME: UDP Data transmission does not work
|
||||
for (uint32_t tb = 0; tb < ue_dl.pdsch_cfg.grant.nof_tb; tb++) {
|
||||
srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRINT_CHANGE_SCHEDULIGN
|
||||
|
@ -595,9 +665,13 @@ int main(int argc, char **argv) {
|
|||
|
||||
nof_trials++;
|
||||
|
||||
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1);
|
||||
rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05);
|
||||
noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05);
|
||||
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);
|
||||
noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f);
|
||||
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;
|
||||
|
@ -605,25 +679,78 @@ int main(int argc, char **argv) {
|
|||
if (isnan(noise)) {
|
||||
noise = 0;
|
||||
}
|
||||
if (isnan(rsrp)) {
|
||||
rsrp = 0;
|
||||
}
|
||||
if (isnan(rsrp0)) {
|
||||
rsrp1 = 0;
|
||||
}
|
||||
if (isnan(rsrp0)) {
|
||||
rsrp1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Plot and Printf
|
||||
if (srslte_ue_sync_get_sfidx(&ue_sync) == 5) {
|
||||
if (srslte_ue_sync_get_sfidx(&ue_sync) == 5 && sfn % 20 == 0) {
|
||||
float gain = prog_args.rf_gain;
|
||||
if (gain < 0) {
|
||||
gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc));
|
||||
}
|
||||
printf("CFO: %+6.2f kHz, "
|
||||
"SNR: %4.1f dB, "
|
||||
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r",
|
||||
|
||||
srslte_ue_sync_get_cfo(&ue_sync)/1000,
|
||||
10*log10(rsrp/noise),
|
||||
100*(1-(float) ue_dl.nof_detected/nof_trials),
|
||||
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total);
|
||||
|
||||
/* Print transmission scheme */
|
||||
if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
|
||||
PRINT_LINE(" Tx scheme: %s (codebook_idx=%d)", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type),
|
||||
ue_dl.pdsch_cfg.codebook_idx);
|
||||
} else {
|
||||
PRINT_LINE(" Tx scheme: %s", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type));
|
||||
}
|
||||
|
||||
/* Print basic Parameters */
|
||||
PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers);
|
||||
PRINT_LINE("nof codewords: %d", ue_dl.pdsch_cfg.grant.nof_tb);
|
||||
PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000);
|
||||
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(" 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,
|
||||
ue_dl.pdsch_cfg.grant.mcs[1].tbs);
|
||||
|
||||
/* MIMO: if tx and rx antennas are bigger than 1 */
|
||||
if (cell.nof_ports > 1 && ue_dl.pdsch.nof_rx_antennas > 1) {
|
||||
/* Compute condition number */
|
||||
srslte_ue_dl_ri_select(&ue_dl, NULL, &cn);
|
||||
|
||||
/* Print condition number */
|
||||
PRINT_LINE(" κ: %.1f dB (Condition number, 0 dB => Best)", cn);
|
||||
}
|
||||
PRINT_LINE("");
|
||||
|
||||
/* Spatial multiplex only */
|
||||
if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
|
||||
|
||||
/* Compute Rank Indicator (RI) and Precoding Matrix Indicator (PMI) */
|
||||
srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, NULL);
|
||||
for (uint32_t nl = 0; nl < SRSLTE_MAX_LAYERS; nl++) {
|
||||
for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb++) {
|
||||
sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print Multiplex stats */
|
||||
PRINT_LINE("SINR (dB) Vs RI and PMI:");
|
||||
PRINT_LINE(" | RI | 1 | 2 |");
|
||||
PRINT_LINE(" -------+-------+-------+");
|
||||
PRINT_LINE(" P | 0 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][0]), (ri == 1 && pmi == 0) ? '*' : ' ',
|
||||
10 * log10(sinr[1][0]), (ri == 2 && pmi == 0) ? '*' : ' ');
|
||||
PRINT_LINE(" M | 1 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][1]), (ri == 1 && pmi == 1) ? '*' : ' ',
|
||||
10 * log10(sinr[1][1]), (ri == 2 && pmi == 1) ? '*' : ' ');
|
||||
PRINT_LINE(" I | 2 | %5.2f%c|-------+ ", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2) ? '*' : ' ');
|
||||
PRINT_LINE(" | 3 | %5.2f%c| ", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3) ? '*' : ' ');
|
||||
PRINT_LINE("");
|
||||
}
|
||||
PRINT_LINE("Press enter maximum printing debug log of 1 subframe.");
|
||||
PRINT_LINE("");
|
||||
PRINT_LINE_RESET_CURSOR();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -631,7 +758,7 @@ int main(int argc, char **argv) {
|
|||
sfn++;
|
||||
if (sfn == 1024) {
|
||||
sfn = 0;
|
||||
printf("\n");
|
||||
PRINT_LINE_ADVANCE_CURSOR();
|
||||
ue_dl.pkt_errors = 0;
|
||||
ue_dl.pkts_total = 0;
|
||||
ue_dl.nof_detected = 0;
|
||||
|
@ -663,7 +790,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
sf_cnt++;
|
||||
} // Main loop
|
||||
|
||||
printf("\033[30B\n");
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
if (!prog_args.disable_plots) {
|
||||
if (!pthread_kill(plot_thread, 0)) {
|
||||
|
@ -674,6 +802,16 @@ int main(int argc, char **argv) {
|
|||
#endif
|
||||
srslte_ue_dl_free(&ue_dl);
|
||||
srslte_ue_sync_free(&ue_sync);
|
||||
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
if (data[i]) {
|
||||
free(data[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < prog_args.rf_nof_rx_ant; i++) {
|
||||
if (sf_buffer[i]) {
|
||||
free(sf_buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_RF
|
||||
if (!prog_args.input_file_name) {
|
||||
|
@ -742,7 +880,7 @@ void *plot_thread_run(void *arg) {
|
|||
while(1) {
|
||||
sem_wait(&plot_sem);
|
||||
|
||||
uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits.nof_re;
|
||||
uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits[0].nof_re;
|
||||
if (!prog_args.disable_plots_except_constellation) {
|
||||
for (i = 0; i < nof_re; i++) {
|
||||
tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i]));
|
||||
|
@ -784,7 +922,7 @@ void *plot_thread_run(void *arg) {
|
|||
plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36*ue_dl.pdcch.nof_cce);
|
||||
}
|
||||
|
||||
plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d, nof_symbols);
|
||||
plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols);
|
||||
|
||||
if (plot_sf_idx == 1) {
|
||||
if (prog_args.net_port_signal > 0) {
|
||||
|
|
|
@ -44,6 +44,7 @@ char *output_file_name;
|
|||
char *rf_args="";
|
||||
float rf_gain=40.0, rf_freq=-1.0, rf_rate=0.96e6;
|
||||
int nof_samples = -1;
|
||||
int nof_rx_antennas = 1;
|
||||
|
||||
void int_handler(int dummy) {
|
||||
keep_running = false;
|
||||
|
@ -55,12 +56,13 @@ void usage(char *prog) {
|
|||
printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain);
|
||||
printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate);
|
||||
printf("\t-n nof_samples [Default %d]\n", nof_samples);
|
||||
printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas);
|
||||
printf("\t-v srslte_verbose\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "agrnvfo")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "agrnvfoA")) != -1) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
output_file_name = argv[optind];
|
||||
|
@ -80,6 +82,9 @@ void parse_args(int argc, char **argv) {
|
|||
case 'n':
|
||||
nof_samples = atoi(argv[optind]);
|
||||
break;
|
||||
case 'A':
|
||||
nof_rx_antennas = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
|
@ -95,11 +100,11 @@ void parse_args(int argc, char **argv) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
cf_t *buffer;
|
||||
cf_t *buffer[SRSLTE_MAX_PORTS];
|
||||
int sample_count, n;
|
||||
srslte_rf_t rf;
|
||||
srslte_filesink_t sink;
|
||||
int32_t buflen;
|
||||
uint32_t buflen;
|
||||
|
||||
signal(SIGINT, int_handler);
|
||||
|
||||
|
@ -107,17 +112,19 @@ int main(int argc, char **argv) {
|
|||
|
||||
buflen = 4800;
|
||||
sample_count = 0;
|
||||
|
||||
buffer = malloc(sizeof(cf_t) * buflen);
|
||||
if (!buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
|
||||
for (int i = 0; i < nof_rx_antennas; i++) {
|
||||
buffer[i] = malloc(sizeof(cf_t) * buflen);
|
||||
if (!buffer[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN);
|
||||
|
||||
printf("Opening RF device...\n");
|
||||
if (srslte_rf_open(&rf, rf_args)) {
|
||||
if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) {
|
||||
fprintf(stderr, "Error opening rf\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -151,18 +158,23 @@ int main(int argc, char **argv) {
|
|||
|
||||
while((sample_count < nof_samples || nof_samples == -1)
|
||||
&& keep_running){
|
||||
n = srslte_rf_recv(&rf, buffer, buflen, 1);
|
||||
n = srslte_rf_recv_with_time_multi(&rf, (void**) buffer, buflen, true, NULL, NULL);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error receiving samples\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
srslte_filesink_write(&sink, buffer, buflen);
|
||||
srslte_filesink_write_multi(&sink, (void**) buffer, buflen, nof_rx_antennas);
|
||||
sample_count += buflen;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nof_rx_antennas; i++) {
|
||||
if (buffer[i]) {
|
||||
free(buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
srslte_filesink_free(&sink);
|
||||
free(buffer);
|
||||
srslte_rf_close(&rf);
|
||||
|
||||
printf("Ok - wrote %d samples\n", sample_count);
|
||||
|
|
|
@ -45,6 +45,7 @@ float rf_gain=60.0, rf_freq=-1.0;
|
|||
int nof_prb = 6;
|
||||
int nof_subframes = -1;
|
||||
int N_id_2 = -1;
|
||||
uint32_t nof_rx_antennas = 1;
|
||||
|
||||
void int_handler(int dummy) {
|
||||
keep_running = false;
|
||||
|
@ -56,12 +57,13 @@ void usage(char *prog) {
|
|||
printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain);
|
||||
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-n nof_subframes [Default %d]\n", nof_subframes);
|
||||
printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas);
|
||||
printf("\t-v verbose\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "agpnvfol")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "agpnvfolA")) != -1) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
output_file_name = argv[optind];
|
||||
|
@ -84,6 +86,9 @@ void parse_args(int argc, char **argv) {
|
|||
case 'l':
|
||||
N_id_2 = atoi(argv[optind]);
|
||||
break;
|
||||
case 'A':
|
||||
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
|
@ -100,7 +105,7 @@ void parse_args(int argc, char **argv) {
|
|||
|
||||
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);
|
||||
return srslte_rf_recv(h, data[0], nsamples, 1);
|
||||
return srslte_rf_recv_with_time_multi(h, (void**) data, nsamples, true, NULL, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -118,13 +123,15 @@ int main(int argc, char **argv) {
|
|||
srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN);
|
||||
|
||||
printf("Opening RF device...\n");
|
||||
if (srslte_rf_open(&rf, rf_args)) {
|
||||
if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) {
|
||||
fprintf(stderr, "Error opening rf\n");
|
||||
exit(-1);
|
||||
}
|
||||
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
|
||||
|
||||
buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
|
||||
for (int i = 0; i< SRSLTE_MAX_PORTS; i++) {
|
||||
buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100));
|
||||
}
|
||||
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
|
@ -158,7 +165,7 @@ int main(int argc, char **argv) {
|
|||
cell.nof_prb = nof_prb;
|
||||
cell.nof_ports = 1;
|
||||
|
||||
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) {
|
||||
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, nof_rx_antennas, (void*) &rf)) {
|
||||
fprintf(stderr, "Error initiating ue_sync\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -181,7 +188,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
} else {
|
||||
printf("Writing to file %6d subframes...\r", subframe_count);
|
||||
srslte_filesink_write(&sink, buffer[0], SRSLTE_SF_LEN_PRB(nof_prb));
|
||||
srslte_filesink_write_multi(&sink, (void**) buffer, SRSLTE_SF_LEN_PRB(nof_prb),nof_rx_antennas);
|
||||
subframe_count++;
|
||||
}
|
||||
}
|
||||
|
@ -196,6 +203,12 @@ int main(int argc, char **argv) {
|
|||
srslte_rf_close(&rf);
|
||||
srslte_ue_sync_free(&ue_sync);
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
if (buffer[i]) {
|
||||
free(buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Ok - wrote %d subframes\n", subframe_count);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -277,10 +277,10 @@ public:
|
|||
uint32_t pid;
|
||||
uint32_t tti;
|
||||
uint32_t last_tti;
|
||||
bool ndi;
|
||||
bool last_ndi;
|
||||
uint32_t n_bytes;
|
||||
int rv;
|
||||
bool ndi[SRSLTE_MAX_CODEWORDS];
|
||||
bool last_ndi[SRSLTE_MAX_CODEWORDS];
|
||||
uint32_t n_bytes[SRSLTE_MAX_CODEWORDS];
|
||||
int rv[SRSLTE_MAX_CODEWORDS];
|
||||
uint16_t rnti;
|
||||
bool is_from_rar;
|
||||
bool is_sps_release;
|
||||
|
@ -291,28 +291,28 @@ public:
|
|||
|
||||
typedef struct {
|
||||
bool decode_enabled;
|
||||
int rv;
|
||||
int rv[SRSLTE_MAX_TB];
|
||||
uint16_t rnti;
|
||||
bool generate_ack;
|
||||
bool default_ack;
|
||||
// If non-null, called after tb_decoded_ok to determine if ack needs to be sent
|
||||
bool (*generate_ack_callback)(void*);
|
||||
void *generate_ack_callback_arg;
|
||||
uint8_t *payload_ptr;
|
||||
srslte_softbuffer_rx_t *softbuffer;
|
||||
uint8_t *payload_ptr[SRSLTE_MAX_TB];
|
||||
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB];
|
||||
srslte_phy_grant_t phy_grant;
|
||||
} tb_action_dl_t;
|
||||
|
||||
typedef struct {
|
||||
bool tx_enabled;
|
||||
bool expect_ack;
|
||||
uint32_t rv;
|
||||
uint32_t rv[SRSLTE_MAX_TB];
|
||||
uint16_t rnti;
|
||||
uint32_t current_tx_nb;
|
||||
int32_t tti_offset; // relative offset between grant and UL tx/HARQ rx
|
||||
srslte_softbuffer_tx_t *softbuffer;
|
||||
srslte_softbuffer_tx_t *softbuffers;
|
||||
srslte_phy_grant_t phy_grant;
|
||||
uint8_t *payload_ptr;
|
||||
uint8_t *payload_ptr[SRSLTE_MAX_TB];
|
||||
} tb_action_ul_t;
|
||||
|
||||
/* Indicate reception of UL grant.
|
||||
|
@ -329,7 +329,7 @@ public:
|
|||
virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0;
|
||||
|
||||
/* Indicate successfull decoding of PDSCH TB. */
|
||||
virtual void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0;
|
||||
virtual void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0;
|
||||
|
||||
/* Indicate successfull decoding of BCH TB through PBCH */
|
||||
virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0;
|
||||
|
|
|
@ -132,6 +132,9 @@ SRSLTE_API float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q);
|
|||
|
||||
SRSLTE_API float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q);
|
||||
|
||||
SRSLTE_API float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q,
|
||||
uint32_t port);
|
||||
|
||||
SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -52,9 +52,12 @@
|
|||
#define SRSLTE_MAX_PORTS 4
|
||||
#define SRSLTE_MAX_LAYERS 4
|
||||
#define SRSLTE_MAX_CODEWORDS 2
|
||||
#define SRSLTE_MAX_TB SRSLTE_MAX_CODEWORDS
|
||||
|
||||
#define SRSLTE_MAX_CODEBLOCKS 32
|
||||
|
||||
#define SRSLTE_MAX_CODEBOOKS 4
|
||||
|
||||
#define SRSLTE_LTE_CRC24A 0x1864CFB
|
||||
#define SRSLTE_LTE_CRC24B 0X1800063
|
||||
#define SRSLTE_LTE_CRC16 0x11021
|
||||
|
@ -148,12 +151,12 @@ typedef enum SRSLTE_API {
|
|||
} srslte_phich_resources_t;
|
||||
|
||||
typedef enum {
|
||||
SRSLTE_RNTI_USER = 0,
|
||||
SRSLTE_RNTI_SI,
|
||||
SRSLTE_RNTI_RAR,
|
||||
SRSLTE_RNTI_TEMP,
|
||||
SRSLTE_RNTI_SPS,
|
||||
SRSLTE_RNTI_PCH,
|
||||
SRSLTE_RNTI_USER = 0, /* Cell RNTI */
|
||||
SRSLTE_RNTI_SI, /* System Information RNTI */
|
||||
SRSLTE_RNTI_RAR, /* Random Access RNTI */
|
||||
SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */
|
||||
SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */
|
||||
SRSLTE_RNTI_PCH, /* Paging RNTI */
|
||||
SRSLTE_RNTI_NOF_TYPES
|
||||
} srslte_rnti_type_t;
|
||||
|
||||
|
@ -173,6 +176,11 @@ typedef enum SRSLTE_API {
|
|||
SRSLTE_MIMO_TYPE_CDD
|
||||
} srslte_mimo_type_t;
|
||||
|
||||
typedef enum SRSLTE_API {
|
||||
SRSLTE_MIMO_DECODER_ZF,
|
||||
SRSLTE_MIMO_DECODER_MMSE
|
||||
} srslte_mimo_decoder_t;
|
||||
|
||||
typedef enum SRSLTE_API {
|
||||
SRSLTE_MOD_BPSK = 0,
|
||||
SRSLTE_MOD_QPSK,
|
||||
|
@ -247,6 +255,8 @@ SRSLTE_API float srslte_coderate(uint32_t tbs,
|
|||
|
||||
SRSLTE_API char *srslte_cp_string(srslte_cp_t cp);
|
||||
|
||||
SRSLTE_API srslte_mod_t srslte_str2mod (char * mod_str);
|
||||
|
||||
SRSLTE_API char *srslte_mod_string(srslte_mod_t mod);
|
||||
|
||||
SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod);
|
||||
|
@ -276,6 +286,8 @@ SRSLTE_API int srslte_band_get_fd_region(enum band_geographical_area region,
|
|||
SRSLTE_API int srslte_str2mimotype(char *mimo_type_str,
|
||||
srslte_mimo_type_t *type);
|
||||
|
||||
SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type);
|
||||
|
||||
SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1,
|
||||
uint32_t tti2);
|
||||
|
||||
|
|
|
@ -152,11 +152,11 @@ SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q,
|
|||
|
||||
SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q,
|
||||
srslte_ra_dl_grant_t *grant,
|
||||
srslte_softbuffer_tx_t *softbuffer,
|
||||
srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS],
|
||||
uint16_t rnti,
|
||||
uint32_t rv_idx,
|
||||
uint32_t sf_idx,
|
||||
uint8_t *data);
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS]);
|
||||
|
||||
SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q,
|
||||
srslte_ra_dl_dci_t *grant,
|
||||
|
|
|
@ -59,4 +59,9 @@ SRSLTE_API int srslte_filesink_write(srslte_filesink_t *q,
|
|||
void *buffer,
|
||||
int nsamples);
|
||||
|
||||
SRSLTE_API int srslte_filesink_write_multi(srslte_filesink_t *q,
|
||||
void **buffer,
|
||||
int nsamples,
|
||||
int nchannels);
|
||||
|
||||
#endif // FILESINK_
|
||||
|
|
|
@ -62,4 +62,9 @@ SRSLTE_API int srslte_filesource_read(srslte_filesource_t *q,
|
|||
void *buffer,
|
||||
int nsamples);
|
||||
|
||||
SRSLTE_API int srslte_filesource_read_multi(srslte_filesource_t *q,
|
||||
void **buffer,
|
||||
int nsamples,
|
||||
int nof_channels);
|
||||
|
||||
#endif // FILESOURCE_
|
||||
|
|
|
@ -65,8 +65,9 @@ SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS],
|
|||
SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
|
||||
cf_t *y[SRSLTE_MAX_PORTS],
|
||||
int nof_layers,
|
||||
int nof_ports,
|
||||
int nof_symbols,
|
||||
int nof_ports,
|
||||
int codebook_idx,
|
||||
int nof_symbols,
|
||||
srslte_mimo_type_t type);
|
||||
|
||||
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "h"
|
||||
|
@ -106,14 +107,31 @@ SRSLTE_API int srslte_predecoding_type(cf_t *y,
|
|||
srslte_mimo_type_t type,
|
||||
float noise_estimate);
|
||||
|
||||
SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder);
|
||||
|
||||
SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS],
|
||||
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
cf_t *x[SRSLTE_MAX_LAYERS],
|
||||
int nof_rxant,
|
||||
int nof_ports,
|
||||
int nof_layers,
|
||||
int codebook_idx,
|
||||
int nof_symbols,
|
||||
srslte_mimo_type_t type,
|
||||
float noise_estimate);
|
||||
|
||||
SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
uint32_t nof_symbols,
|
||||
float noise_estimate,
|
||||
int nof_layers,
|
||||
uint32_t *pmi,
|
||||
float sinr[SRSLTE_MAX_CODEBOOKS]);
|
||||
|
||||
SRSLTE_API int srslte_precoding_cn(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
uint32_t nof_tx_antennas,
|
||||
uint32_t nof_rx_antennas,
|
||||
uint32_t nof_symbols,
|
||||
float *cn);
|
||||
|
||||
|
||||
#endif /* PRECODING_H_ */
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
typedef struct {
|
||||
bool configured;
|
||||
uint32_t pmi_idx;
|
||||
bool simul_cqi_ack;
|
||||
uint32_t ri_idx;
|
||||
bool simul_cqi_ack;
|
||||
bool format_is_subband;
|
||||
uint32_t subband_size;
|
||||
} srslte_cqi_periodic_cfg_t;
|
||||
|
@ -137,7 +138,11 @@ SRSLTE_API int srslte_cqi_format2_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BIT
|
|||
srslte_cqi_format2_subband_t *msg);
|
||||
|
||||
SRSLTE_API bool srslte_cqi_send(uint32_t I_cqi_pmi,
|
||||
uint32_t tti);
|
||||
uint32_t tti);
|
||||
|
||||
SRSLTE_API bool srslte_ri_send(uint32_t I_cqi_pmi,
|
||||
uint32_t I_ri,
|
||||
uint32_t tti);
|
||||
|
||||
SRSLTE_API uint8_t srslte_cqi_from_snr(float snr);
|
||||
|
||||
|
|
|
@ -88,11 +88,26 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q,
|
|||
srslte_regs_t *regs,
|
||||
srslte_cell_t cell);
|
||||
|
||||
SRSLTE_API int srslte_pdcch_init_tx(srslte_pdcch_t *q,
|
||||
srslte_regs_t *regs,
|
||||
srslte_cell_t cell);
|
||||
|
||||
SRSLTE_API int srslte_pdcch_init_rx(srslte_pdcch_t *q,
|
||||
srslte_regs_t *regs,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas);
|
||||
|
||||
SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q,
|
||||
srslte_regs_t *regs,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas);
|
||||
|
||||
SRSLTE_API int srslte_pdcch_init_txrx(srslte_pdcch_t *q,
|
||||
srslte_regs_t *regs,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas,
|
||||
bool isReceiver);
|
||||
|
||||
SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q);
|
||||
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include "srslte/phy/phch/pdsch_cfg.h"
|
||||
|
||||
typedef struct {
|
||||
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
|
||||
srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NSUBFRAMES_X_FRAME];
|
||||
bool sequence_generated;
|
||||
} srslte_pdsch_user_t;
|
||||
|
||||
|
@ -62,11 +62,11 @@ typedef struct SRSLTE_API {
|
|||
|
||||
/* 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;
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */
|
||||
cf_t *symbols[SRSLTE_MAX_PORTS]; /* PDSCH Encoded/Decoded Symbols */
|
||||
cf_t *x[SRSLTE_MAX_LAYERS]; /* Layer mapped */
|
||||
cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */
|
||||
void *e[SRSLTE_MAX_CODEWORDS];
|
||||
|
||||
/* tx & rx objects */
|
||||
srslte_modem_table_t mod[4];
|
||||
|
@ -75,15 +75,15 @@ typedef struct SRSLTE_API {
|
|||
srslte_pdsch_user_t **users;
|
||||
|
||||
srslte_sch_t dl_sch;
|
||||
|
||||
|
||||
} srslte_pdsch_t;
|
||||
|
||||
SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q,
|
||||
srslte_cell_t cell);
|
||||
SRSLTE_API int srslte_pdsch_init_tx(srslte_pdsch_t *q,
|
||||
srslte_cell_t cell);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_init_multi(srslte_pdsch_t *q,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas);
|
||||
SRSLTE_API int srslte_pdsch_init_rx(srslte_pdsch_t *q,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_antennas);
|
||||
|
||||
SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q);
|
||||
|
||||
|
@ -98,34 +98,50 @@ SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg,
|
|||
srslte_ra_dl_grant_t *grant,
|
||||
uint32_t cfi,
|
||||
uint32_t sf_idx,
|
||||
uint32_t rvidx);
|
||||
int rvidx);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg,
|
||||
srslte_cell_t cell,
|
||||
srslte_ra_dl_grant_t *grant,
|
||||
uint32_t cfi,
|
||||
uint32_t sf_idx,
|
||||
int rvidx[SRSLTE_MAX_CODEWORDS],
|
||||
srslte_mimo_type_t mimo_type,
|
||||
uint32_t pmi);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_tx_t *softbuffer,
|
||||
uint8_t *data,
|
||||
uint16_t rnti,
|
||||
cf_t *sf_symbols[SRSLTE_MAX_PORTS]);
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
||||
uint16_t rnti,
|
||||
cf_t *sf_symbols[SRSLTE_MAX_PORTS]);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_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,
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
|
||||
cf_t *sf_symbols[SRSLTE_MAX_PORTS],
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint16_t rnti,
|
||||
uint8_t *data);
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
||||
bool acks[SRSLTE_MAX_CODEWORDS]);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_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 rnti,
|
||||
uint8_t *data);
|
||||
SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint32_t nof_ce,
|
||||
uint32_t pmi[SRSLTE_MAX_LAYERS],
|
||||
float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]);
|
||||
|
||||
SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q);
|
||||
SRSLTE_API int srslte_pdsch_cn_compute(srslte_pdsch_t *q,
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
uint32_t nof_ce,
|
||||
float *cn);
|
||||
|
||||
SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter);
|
||||
|
||||
SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q);
|
||||
|
||||
SRSLTE_API uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q);
|
||||
|
||||
|
|
|
@ -40,11 +40,14 @@
|
|||
#include "srslte/phy/fec/cbsegm.h"
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_cbsegm_t cb_segm;
|
||||
srslte_ra_dl_grant_t grant;
|
||||
srslte_ra_nbits_t nbits;
|
||||
uint32_t rv;
|
||||
uint32_t sf_idx;
|
||||
srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS];
|
||||
srslte_ra_dl_grant_t grant;
|
||||
srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS];
|
||||
uint32_t rv[SRSLTE_MAX_CODEWORDS];
|
||||
uint32_t sf_idx;
|
||||
uint32_t nof_layers;
|
||||
uint32_t codebook_idx;
|
||||
srslte_mimo_type_t mimo_type;
|
||||
} srslte_pdsch_cfg_t;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -102,11 +102,10 @@ typedef struct SRSLTE_API {
|
|||
typedef struct SRSLTE_API {
|
||||
bool prb_idx[2][SRSLTE_MAX_PRB];
|
||||
uint32_t nof_prb;
|
||||
uint32_t Qm;
|
||||
uint32_t Qm2;
|
||||
srslte_ra_mcs_t mcs;
|
||||
srslte_ra_mcs_t mcs2;
|
||||
uint32_t Qm[SRSLTE_MAX_CODEWORDS];
|
||||
srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS];
|
||||
uint32_t nof_tb;
|
||||
uint32_t pinfo;
|
||||
} srslte_ra_dl_grant_t;
|
||||
|
||||
/** Unpacked DCI message for DL grant */
|
||||
|
@ -206,10 +205,10 @@ SRSLTE_API int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci,
|
|||
SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant,
|
||||
uint32_t cfi,
|
||||
srslte_cell_t cell,
|
||||
uint32_t sf_idx,
|
||||
srslte_ra_nbits_t *nbits);
|
||||
uint32_t sf_idx,
|
||||
srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]);
|
||||
|
||||
SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell,
|
||||
SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell,
|
||||
uint32_t nof_prb,
|
||||
uint32_t nof_ctrl_symbols);
|
||||
|
||||
|
|
|
@ -96,12 +96,26 @@ SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q,
|
|||
uint8_t *data,
|
||||
uint8_t *e_bits);
|
||||
|
||||
SRSLTE_API int srslte_dlsch_encode2(srslte_sch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_tx_t *softbuffer,
|
||||
uint8_t *data,
|
||||
uint8_t *e_bits,
|
||||
int codeword_idx);
|
||||
|
||||
SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_rx_t *softbuffer,
|
||||
int16_t *e_bits,
|
||||
uint8_t *data);
|
||||
|
||||
SRSLTE_API int srslte_dlsch_decode2(srslte_sch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_rx_t *softbuffer,
|
||||
int16_t *e_bits,
|
||||
uint8_t *data,
|
||||
int codeword_idx);
|
||||
|
||||
SRSLTE_API int srslte_ulsch_encode(srslte_sch_t *q,
|
||||
srslte_pusch_cfg_t *cfg,
|
||||
srslte_softbuffer_tx_t *softbuffer,
|
||||
|
|
|
@ -73,9 +73,9 @@ SRSLTE_API int srslte_rf_open(srslte_rf_t *h,
|
|||
|
||||
SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h,
|
||||
char *args,
|
||||
uint32_t nof_rx_antennas);
|
||||
uint32_t nof_rx_antennas);
|
||||
|
||||
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
|
||||
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
|
||||
char *devname,
|
||||
char *args);
|
||||
|
||||
|
@ -200,5 +200,21 @@ SRSLTE_API int srslte_rf_send_timed2(srslte_rf_t *h,
|
|||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
|
||||
SRSLTE_API int srslte_rf_send_timed_multi(srslte_rf_t *rf,
|
||||
void *data[4],
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
|
||||
SRSLTE_API int srslte_rf_send_multi(srslte_rf_t *rf,
|
||||
void *data[4],
|
||||
int nsamples,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ typedef struct SRSLTE_API {
|
|||
srslte_cfo_t sfo_correct;
|
||||
|
||||
srslte_pdsch_cfg_t pdsch_cfg;
|
||||
srslte_softbuffer_rx_t softbuffer;
|
||||
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
|
||||
srslte_ra_dl_dci_t dl_dci;
|
||||
srslte_cell_t cell;
|
||||
|
||||
|
@ -94,7 +94,12 @@ typedef struct SRSLTE_API {
|
|||
cf_t *sf_symbols_m[SRSLTE_MAX_PORTS];
|
||||
cf_t *ce[SRSLTE_MAX_PORTS]; // compatibility
|
||||
cf_t *ce_m[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
|
||||
|
||||
|
||||
/* RI, PMI and SINR for MIMO statistics */
|
||||
float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS];
|
||||
uint32_t pmi[SRSLTE_MAX_LAYERS];
|
||||
uint32_t ri;
|
||||
|
||||
srslte_dci_format_t dci_format;
|
||||
uint64_t pkt_errors;
|
||||
uint64_t pkts_total;
|
||||
|
@ -113,21 +118,13 @@ typedef struct SRSLTE_API {
|
|||
}srslte_ue_dl_t;
|
||||
|
||||
/* This function shall be called just after the initial synchronization */
|
||||
SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q,
|
||||
srslte_cell_t cell);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas);
|
||||
SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas);
|
||||
|
||||
SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
|
||||
cf_t *input,
|
||||
uint32_t sf_idx,
|
||||
uint32_t *cfi);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q,
|
||||
SRSLTE_API 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);
|
||||
|
@ -136,11 +133,12 @@ SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
|
|||
uint32_t sf_idx,
|
||||
uint32_t *cfi);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
|
||||
srslte_ra_dl_grant_t *grant,
|
||||
uint32_t cfi,
|
||||
uint32_t sf_idx,
|
||||
uint32_t rvidx);
|
||||
SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
|
||||
srslte_ra_dl_grant_t *grant,
|
||||
uint32_t cfi,
|
||||
uint32_t sf_idx,
|
||||
int rvidx[SRSLTE_MAX_CODEWORDS],
|
||||
srslte_mimo_type_t mimo_type);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q,
|
||||
uint32_t cfi,
|
||||
|
@ -149,12 +147,14 @@ SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q,
|
|||
srslte_dci_msg_t *dci_msg);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q,
|
||||
uint32_t tm,
|
||||
uint32_t cfi,
|
||||
uint32_t sf_idx,
|
||||
uint16_t rnti,
|
||||
srslte_dci_msg_t *dci_msg);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q,
|
||||
uint32_t tm,
|
||||
uint32_t cfi,
|
||||
uint32_t sf_idx,
|
||||
uint16_t rnti,
|
||||
|
@ -166,27 +166,29 @@ SRSLTE_API uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q);
|
|||
SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q,
|
||||
float sample_offset);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q,
|
||||
cf_t *input,
|
||||
uint8_t *data,
|
||||
uint32_t tti);
|
||||
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q,
|
||||
cf_t *input[SRSLTE_MAX_PORTS],
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
||||
uint32_t tm,
|
||||
uint32_t tti,
|
||||
bool acks[SRSLTE_MAX_CODEWORDS]);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q,
|
||||
cf_t *input[SRSLTE_MAX_PORTS],
|
||||
uint8_t *data,
|
||||
uint32_t tti);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q,
|
||||
cf_t *input,
|
||||
uint8_t *data,
|
||||
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q,
|
||||
cf_t *input[SRSLTE_MAX_PORTS],
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
||||
uint32_t tm,
|
||||
uint32_t tti,
|
||||
uint16_t rnti);
|
||||
uint16_t rnti,
|
||||
bool acks[SRSLTE_MAX_CODEWORDS]);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q,
|
||||
cf_t *input[SRSLTE_MAX_PORTS],
|
||||
uint8_t *data,
|
||||
uint32_t tti,
|
||||
uint16_t rnti);
|
||||
SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q,
|
||||
uint32_t *ri,
|
||||
uint32_t *pmi,
|
||||
float *current_sinr);
|
||||
|
||||
SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q,
|
||||
uint32_t *ri,
|
||||
float *cn);
|
||||
|
||||
SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q,
|
||||
uint32_t sf_idx,
|
||||
|
|
|
@ -148,6 +148,13 @@ SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q,
|
|||
int offset_time,
|
||||
float offset_freq);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q,
|
||||
uint32_t nof_prb,
|
||||
char *file_name,
|
||||
int offset_time,
|
||||
float offset_freq,
|
||||
uint32_t nof_rx_ant);
|
||||
|
||||
SRSLTE_API void srslte_ue_sync_free(srslte_ue_sync_t *q);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q,
|
||||
|
|
|
@ -58,10 +58,16 @@ SRSLTE_API extern int srslte_verbose;
|
|||
#define PRINT_NONE srslte_verbose=SRSLTE_VERBOSE_NONE
|
||||
|
||||
#define DEBUG(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG) \
|
||||
fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__)
|
||||
fprintf(stdout, "[DEBUG]: " _fmt, ##__VA_ARGS__)
|
||||
|
||||
#define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \
|
||||
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
|
||||
fprintf(stdout, "[INFO]: " _fmt, ##__VA_ARGS__)
|
||||
|
||||
#if CMAKE_BUILD_TYPE==Debug
|
||||
/* In debug mode, it prints out the */
|
||||
#define ERROR(_fmt, ...) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__)
|
||||
#endif /* CMAKE_BUILD_TYPE==Debug */
|
||||
|
||||
#endif // DEBUG_H
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
*
|
||||
* \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/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_MAT_H
|
||||
#define SRSLTE_MAT_H
|
||||
|
||||
#include "srslte/phy/utils/simd.h"
|
||||
#include "srslte/config.h"
|
||||
|
||||
/*
|
||||
* Generic Macros
|
||||
*/
|
||||
#define RANDOM_CF() (((float)rand())/((float)RAND_MAX) + _Complex_I*((float)rand())/((float)RAND_MAX))
|
||||
|
||||
/* Generic implementation for complex reciprocal */
|
||||
SRSLTE_API cf_t srslte_mat_cf_recip_gen(cf_t a);
|
||||
|
||||
/* Generic implementation for 2x2 determinant */
|
||||
SRSLTE_API cf_t srslte_mat_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11);
|
||||
|
||||
/* Generic implementation for 2x2 Matrix Inversion */
|
||||
SRSLTE_API void srslte_mat_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11,
|
||||
cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11);
|
||||
|
||||
/* Generic implementation for Zero Forcing (ZF) solver */
|
||||
SRSLTE_API void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1,
|
||||
cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1,
|
||||
float norm);
|
||||
|
||||
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
SRSLTE_API void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1,
|
||||
cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1,
|
||||
float noise_estimate,
|
||||
float norm);
|
||||
|
||||
SRSLTE_API float srslte_mat_2x2_cn(cf_t h00,
|
||||
cf_t h01,
|
||||
cf_t h10,
|
||||
cf_t h11);
|
||||
|
||||
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
||||
/* SSE implementation for complex reciprocal */
|
||||
SRSLTE_API __m128 srslte_mat_cf_recip_sse(__m128 a);
|
||||
|
||||
/* SSE implementation for 2x2 determinant */
|
||||
SRSLTE_API __m128 srslte_mat_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11);
|
||||
|
||||
/* SSE implementation for Zero Forcing (ZF) solver */
|
||||
SRSLTE_API void srslte_mat_2x2_zf_sse(__m128 y0, __m128 y1,
|
||||
__m128 h00, __m128 h01, __m128 h10, __m128 h11,
|
||||
__m128 *x0, __m128 *x1,
|
||||
float norm);
|
||||
|
||||
/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
SRSLTE_API void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1,
|
||||
__m128 h00, __m128 h01, __m128 h10, __m128 h11,
|
||||
__m128 *x0, __m128 *x1,
|
||||
float noise_estimate, float norm);
|
||||
|
||||
#endif /* LV_HAVE_SSE */
|
||||
|
||||
#ifdef LV_HAVE_AVX
|
||||
|
||||
/* AVX implementation for complex reciprocal */
|
||||
SRSLTE_API __m256 srslte_mat_cf_recip_avx(__m256 a);
|
||||
|
||||
/* AVX implementation for 2x2 determinant */
|
||||
SRSLTE_API __m256 srslte_mat_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11);
|
||||
|
||||
/* AVX implementation for Zero Forcing (ZF) solver */
|
||||
SRSLTE_API void srslte_mat_2x2_zf_avx(__m256 y0, __m256 y1,
|
||||
__m256 h00, __m256 h01, __m256 h10, __m256 h11,
|
||||
__m256 *x0, __m256 *x1,
|
||||
float norm);
|
||||
|
||||
/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
SRSLTE_API void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1,
|
||||
__m256 h00, __m256 h01, __m256 h10, __m256 h11,
|
||||
__m256 *x0, __m256 *x1,
|
||||
float noise_estimate, float norm);
|
||||
|
||||
#endif /* LV_HAVE_AVX */
|
||||
|
||||
#endif /* SRSLTE_MAT_H */
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
*
|
||||
* \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/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_SIMD_H_H
|
||||
#define SRSLTE_SIMD_H_H
|
||||
|
||||
/*
|
||||
* SSE Macros
|
||||
*/
|
||||
#ifdef LV_HAVE_SSE
|
||||
#define _MM_SWAP(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,3,0,1)))
|
||||
#define _MM_PERM(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,1,3,0)))
|
||||
#define _MM_MULJ_PS(X) _MM_SWAP(_MM_CONJ_PS(X))
|
||||
#define _MM_CONJ_PS(X) (_mm_xor_ps(X, _mm_set_ps(-0.0f, 0.0f, -0.0f, 0.0f)))
|
||||
#define _MM_SQMOD_PS(X) _MM_PERM(_mm_hadd_ps(_mm_mul_ps(X,X), _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f)))
|
||||
#define _MM_PROD_PS(a, b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(\
|
||||
_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b)))
|
||||
|
||||
#endif /* LV_HAVE_SSE */
|
||||
|
||||
/*
|
||||
* AVX Macros
|
||||
*/
|
||||
#ifdef LV_HAVE_AVX
|
||||
|
||||
#define _MM256_MULJ_PS(X) _mm256_permute_ps(_MM256_CONJ_PS(X), 0b10110001)
|
||||
#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, _mm256_set_ps(-0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f)))
|
||||
|
||||
#ifdef LV_HAVE_FMA
|
||||
#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_mul_ps(B,B)), \
|
||||
_mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100)
|
||||
#define _MM256_PROD_PS(a, b) _mm256_fmaddsub_ps(a,_mm256_moveldup_ps(b),\
|
||||
_mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b)))
|
||||
#else
|
||||
#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_add_ps(_mm256_mul_ps(A,A), _mm256_mul_ps(B,B)), \
|
||||
_mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100)
|
||||
#define _MM256_PROD_PS(a, b) _mm256_addsub_ps(_mm256_mul_ps(a,_mm256_moveldup_ps(b)),\
|
||||
_mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b)))
|
||||
#endif /* LV_HAVE_FMA */
|
||||
#endif /* LV_HAVE_AVX */
|
||||
|
||||
|
||||
/*
|
||||
* AVX extension with FMA Macros
|
||||
*/
|
||||
#ifdef LV_HAVE_FMA
|
||||
|
||||
#define _MM256_SQMOD_ADD_PS(A, B, C) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_fmadd_ps(B, B, C)),\
|
||||
_mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100)
|
||||
|
||||
#define _MM256_PROD_ADD_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\
|
||||
_mm256_fmaddsub_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C))
|
||||
|
||||
#define _MM256_PROD_SUB_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\
|
||||
_mm256_fmsubadd_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C))
|
||||
#endif /* LV_HAVE_FMA */
|
||||
|
||||
#endif //SRSLTE_SIMD_H_H
|
|
@ -175,6 +175,9 @@ SRSLTE_API void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t le
|
|||
/* argument of each vector element */
|
||||
SRSLTE_API void srslte_vec_arg_cf(cf_t *x, float *arg, uint32_t len);
|
||||
|
||||
/* Copy 256 bit aligned vector */
|
||||
SRSLTE_API void srs_vec_cf_cpy(cf_t *src, cf_t *dst, int len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -417,12 +417,15 @@ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) {
|
|||
|
||||
}
|
||||
|
||||
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
|
||||
// Note: use only port 0 but average across antennas
|
||||
float n = 0;
|
||||
for (int i=0;i<q->last_nof_antennas;i++) {
|
||||
n += q->rsrp[i][0];
|
||||
float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) {
|
||||
float n = 0;
|
||||
for (int i = 0; i < q->last_nof_antennas; i++) {
|
||||
n += q->rsrp[i][port];
|
||||
}
|
||||
return n/q->last_nof_antennas;
|
||||
return n / q->last_nof_antennas;
|
||||
}
|
||||
|
||||
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
|
||||
// Note: use only port 0 but average across antennas
|
||||
return srslte_chest_dl_get_rsrp_port(q, 0);
|
||||
}
|
||||
|
|
|
@ -52,4 +52,3 @@ add_test(chest_test_ul_cellid1 chest_test_ul -c 2 -r 50)
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -124,6 +124,24 @@ bool srslte_N_id_1_isvalid(uint32_t N_id_1) {
|
|||
}
|
||||
}
|
||||
|
||||
srslte_mod_t srslte_str2mod (char * mod_str) {
|
||||
int i = 0;
|
||||
|
||||
/* Upper case */
|
||||
while (mod_str[i] &= (~' '), mod_str[++i]);
|
||||
|
||||
if (!strcmp(mod_str, "QPSK")) {
|
||||
return SRSLTE_MOD_QPSK;
|
||||
} else if (!strcmp(mod_str, "16QAM")) {
|
||||
return SRSLTE_MOD_16QAM;
|
||||
} else if (!strcmp(mod_str, "64QAM")) {
|
||||
return SRSLTE_MOD_64QAM;
|
||||
} else {
|
||||
return (srslte_mod_t) SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
char *srslte_mod_string(srslte_mod_t mod) {
|
||||
switch (mod) {
|
||||
case SRSLTE_MOD_BPSK:
|
||||
|
@ -424,18 +442,40 @@ struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = {
|
|||
|
||||
|
||||
int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) {
|
||||
if (!strcmp(mimo_type_str, "single")) {
|
||||
int i = 0;
|
||||
|
||||
/* Low case */
|
||||
while (mimo_type_str[i] |= ' ', mimo_type_str[++i]);
|
||||
|
||||
if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "port0")) {
|
||||
*type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
} else if (!strcmp(mimo_type_str, "diversity")) {
|
||||
} else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "txdiversity")) {
|
||||
*type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
} else if (!strcmp(mimo_type_str, "multiplex")) {
|
||||
} else if (!strcmp(mimo_type_str, "multiplex") || !strcmp(mimo_type_str, "spatialmux")) {
|
||||
*type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
} else if (!strcmp(mimo_type_str, "cdd")) {
|
||||
*type = SRSLTE_MIMO_TYPE_CDD;
|
||||
} else {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
char *srslte_mimotype2str(srslte_mimo_type_t mimo_type) {
|
||||
switch (mimo_type) {
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
return "Single";
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
return "Diversity";
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
return "Multiplex";
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
return "CDD";
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
float get_fd(struct lte_band *band, uint32_t dl_earfcn) {
|
||||
if (dl_earfcn >= band->dl_earfcn_offset) {
|
||||
return band->fd_low_mhz + 0.1*(dl_earfcn - band->dl_earfcn_offset);
|
||||
|
|
|
@ -83,7 +83,7 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell)
|
|||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_pdsch_init(&q->pdsch, q->cell)) {
|
||||
if (srslte_pdsch_init_tx(&q->pdsch, q->cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
@ -262,9 +262,9 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant,
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer,
|
||||
int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS],
|
||||
uint16_t rnti, uint32_t rv_idx, uint32_t sf_idx,
|
||||
uint8_t *data)
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS])
|
||||
{
|
||||
/* Configure pdsch_cfg parameters */
|
||||
if (srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx)) {
|
||||
|
|
|
@ -99,3 +99,60 @@ int srslte_filesink_write(srslte_filesink_t *q, void *buffer, int nsamples) {
|
|||
return i;
|
||||
}
|
||||
|
||||
int srslte_filesink_write_multi(srslte_filesink_t *q, void **buffer, int nsamples, int nchannels) {
|
||||
int i, j;
|
||||
float **fbuf = (float**) buffer;
|
||||
_Complex float **cbuf = (_Complex float**) buffer;
|
||||
_Complex short **sbuf = (_Complex short**) buffer;
|
||||
int size;
|
||||
|
||||
switch(q->type) {
|
||||
case SRSLTE_FLOAT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
for (j=0;j<nchannels;j++) {
|
||||
fprintf(q->f, "%g%c", fbuf[j][i], (j!=(nchannels-1))?'\t':'\n');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SRSLTE_COMPLEX_FLOAT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
for (j=0;j<nchannels;j++) {
|
||||
fprintf(q->f, "%g%+gi%c", __real__ cbuf[j][i], __imag__ cbuf[j][i], (j!=(nchannels-1))?'\t':'\n');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SRSLTE_COMPLEX_SHORT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
for (j=0;j<nchannels;j++) {
|
||||
fprintf(q->f, "%hd%+hdi%c", __real__ sbuf[j][i], __imag__ sbuf[j][i], (j!=(nchannels-1))?'\t':'\n');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SRSLTE_FLOAT_BIN:
|
||||
case SRSLTE_COMPLEX_FLOAT_BIN:
|
||||
case SRSLTE_COMPLEX_SHORT_BIN:
|
||||
if (q->type == SRSLTE_FLOAT_BIN) {
|
||||
size = sizeof(float);
|
||||
} else if (q->type == SRSLTE_COMPLEX_FLOAT_BIN) {
|
||||
size = sizeof(_Complex float);
|
||||
} else if (q->type == SRSLTE_COMPLEX_SHORT_BIN) {
|
||||
size = sizeof(_Complex short);
|
||||
}
|
||||
if (nchannels > 1) {
|
||||
uint32_t count = 0;
|
||||
for (i = 0; i < nsamples; i++) {
|
||||
for (j = 0; j < nchannels; j++) {
|
||||
count += fwrite(&cbuf[j][i], size, 1, q->f);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
} else {
|
||||
return fwrite(buffer[0], size, nsamples, q->f);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
|
@ -116,3 +116,29 @@ int srslte_filesource_read(srslte_filesource_t *q, void *buffer, int nsamples) {
|
|||
return i;
|
||||
}
|
||||
|
||||
int srslte_filesource_read_multi(srslte_filesource_t *q, void **buffer, int nsamples, int nof_channels) {
|
||||
int i, j, count = 0;
|
||||
_Complex float **cbuf = (_Complex float **) buffer;
|
||||
|
||||
switch (q->type) {
|
||||
case SRSLTE_FLOAT:
|
||||
case SRSLTE_COMPLEX_FLOAT:
|
||||
case SRSLTE_COMPLEX_SHORT:
|
||||
case SRSLTE_FLOAT_BIN:
|
||||
case SRSLTE_COMPLEX_SHORT_BIN:
|
||||
fprintf(stderr, "%s.%d:Read Mode not implemented\n", __FILE__, __LINE__);
|
||||
count = SRSLTE_ERROR;
|
||||
break;
|
||||
case SRSLTE_COMPLEX_FLOAT_BIN:
|
||||
for (i = 0; i < nsamples; i++) {
|
||||
for (j = 0; j < nof_channels; j++) {
|
||||
count += fread(&cbuf[j][i], sizeof(cf_t), (size_t) 1, q->f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
count = SRSLTE_ERROR;
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <srslte/phy/utils/vector.h>
|
||||
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/mimo/layermap.h"
|
||||
|
@ -51,7 +52,12 @@ int srslte_layermap_diversity(cf_t *d, cf_t *x[SRSLTE_MAX_LAYERS], int nof_layer
|
|||
|
||||
int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_cw, int nof_layers,
|
||||
int nof_symbols[SRSLTE_MAX_CODEWORDS]) {
|
||||
if (nof_cw == 1) {
|
||||
if (nof_cw == nof_layers) {
|
||||
for (int i = 0; i < nof_cw; i++) {
|
||||
srs_vec_cf_cpy(x[i], d[i], (uint32_t) nof_symbols[0]);
|
||||
}
|
||||
return nof_symbols[0];
|
||||
} else if (nof_cw == 1) {
|
||||
return srslte_layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
|
||||
} else {
|
||||
int n[2];
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -42,7 +42,7 @@ add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4)
|
|||
|
||||
|
||||
########################################################################
|
||||
# LAYER MAPPING TEST
|
||||
# PRECODING MAPPING TEST
|
||||
########################################################################
|
||||
|
||||
add_executable(precoding_test precoder_test.c)
|
||||
|
@ -52,6 +52,30 @@ add_test(precoding_single precoding_test -n 1000 -m single)
|
|||
add_test(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2)
|
||||
add_test(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4)
|
||||
|
||||
|
||||
add_test(precoding_cdd_2x2_zf precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d zf)
|
||||
add_test(precoding_cdd_2x2_mmse precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d mmse)
|
||||
|
||||
add_test(precoding_multiplex_1l_cb0 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 0)
|
||||
add_test(precoding_multiplex_1l_cb1 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 1)
|
||||
add_test(precoding_multiplex_1l_cb2 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 2)
|
||||
add_test(precoding_multiplex_1l_cb3 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 3)
|
||||
|
||||
add_test(precoding_multiplex_2l_cb0_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d zf)
|
||||
add_test(precoding_multiplex_2l_cb1_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d zf)
|
||||
add_test(precoding_multiplex_2l_cb2_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d zf)
|
||||
|
||||
|
||||
add_test(precoding_multiplex_2l_cb0_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d mmse)
|
||||
add_test(precoding_multiplex_2l_cb1_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d mmse)
|
||||
add_test(precoding_multiplex_2l_cb2_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d mmse)
|
||||
|
||||
########################################################################
|
||||
# PMI SELECT TEST
|
||||
########################################################################
|
||||
|
||||
add_executable(pmi_select_test pmi_select_test.c)
|
||||
target_link_libraries(pmi_select_test srslte_phy)
|
||||
|
||||
add_test(pmi_select_test pmi_select_test)
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ int nof_cw = 1, nof_layers = 1;
|
|||
char *mimo_type_name = NULL;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s -m [single|diversity|multiplex] -c [nof_cw] -l [nof_layers]\n", prog);
|
||||
printf("Usage: %s -m [single|diversity|multiplex|cdd] -c [nof_cw] -l [nof_layers]\n", prog);
|
||||
printf("\t-n num_symbols [Default %d]\n", nof_symbols);
|
||||
}
|
||||
|
||||
|
@ -96,19 +96,19 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
for (i=0;i<nof_cw;i++) {
|
||||
d[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]);
|
||||
d[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symb_cw[i]);
|
||||
if (!d[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
dp[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]);
|
||||
dp[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symb_cw[i]);
|
||||
if (!dp[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
for (i=0;i<nof_layers;i++) {
|
||||
x[i] = malloc(sizeof(cf_t) * nof_symbols);
|
||||
x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
|
||||
if (!x[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
*
|
||||
* \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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <complex.h>
|
||||
|
||||
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include "srslte/phy/mimo/precoding.h"
|
||||
#include "pmi_select_test.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
|
||||
float noise_estimate;
|
||||
float sinr_1l[SRSLTE_MAX_CODEBOOKS];
|
||||
float sinr_2l[SRSLTE_MAX_CODEBOOKS];
|
||||
float cn;
|
||||
uint32_t pmi[2];
|
||||
uint32_t nof_symbols = (uint32_t) SRSLTE_SF_LEN_RE(6, SRSLTE_CP_NORM);
|
||||
int ret = SRSLTE_ERROR;
|
||||
|
||||
/* Allocate channels */
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
|
||||
h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
|
||||
if (!h[i][j]) {
|
||||
goto clean;
|
||||
}
|
||||
bzero(h[i][j], sizeof(cf_t) * nof_symbols);
|
||||
}
|
||||
}
|
||||
|
||||
for (int c = 0; c < PMI_SELECT_TEST_NOF_CASES; c++) {
|
||||
pmi_select_test_case_gold_t *gold = &pmi_select_test_case_gold[c];
|
||||
|
||||
/* Set channel */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
cf_t hij = gold->h[i][j];
|
||||
|
||||
for (int k = 0; k < nof_symbols; k++) {
|
||||
h[i][j][k] = hij;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set noise estimate */
|
||||
noise_estimate = gold->n;
|
||||
|
||||
/* PMI select for 1 layer */
|
||||
ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 1, &pmi[0], sinr_1l);
|
||||
if (ret < 0) {
|
||||
ERROR("During PMI selection for 1 layer");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Check SINR for 1 layer */
|
||||
for (int i = 0; i < ret; i++) {
|
||||
if (fabsf(gold->snri_1l[i] - sinr_1l[i]) > 0.1) {
|
||||
ERROR("Test case %d failed computing 1 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n",
|
||||
c + 1, i, sinr_1l[i], gold->snri_1l[i]);
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check PMI select for 1 layer*/
|
||||
if (pmi[0] != gold->pmi[0]) {
|
||||
ERROR("Test case %d failed computing 1 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[0], gold->pmi[0]);
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* PMI select for 2 layer */
|
||||
ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 2, &pmi[1], sinr_2l);
|
||||
if (ret < 0) {
|
||||
ERROR("During PMI selection for 2 layer");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Check SINR for 2 layer */
|
||||
for (int i = 0; i < ret; i++) {
|
||||
if (fabsf(gold->snri_2l[i] - sinr_2l[i]) > 0.1) {
|
||||
ERROR("Test case %d failed computing 2 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n",
|
||||
c + 1, i, sinr_2l[i], gold->snri_2l[i]);
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check PMI select for 2 layer*/
|
||||
if (pmi[1] != gold->pmi[1]) {
|
||||
ERROR("Test case %d failed computing 2 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[1], gold->pmi[1]);
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Condition number */
|
||||
if (srslte_precoding_cn(h, 2, 2, nof_symbols, &cn)) {
|
||||
ERROR("Test case %d condition number returned error\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Check condition number */
|
||||
if (fabsf(gold->k - cn) > 0.1) {
|
||||
ERROR("Test case %d failed computing condition number (test=%.2f; gold=%.2f)\n",
|
||||
c + 1, cn, gold->k);
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test passed */
|
||||
ret = SRSLTE_SUCCESS;
|
||||
|
||||
clean:
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
|
||||
if (h[i][j]) {
|
||||
free(h[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
printf("Failed!\n");
|
||||
} else {
|
||||
printf("Passed!\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
/**
|
||||
*
|
||||
* \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/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PMI_SELECT_TEST_H
|
||||
#define PMI_SELECT_TEST_H
|
||||
|
||||
#define PMI_SELECT_TEST_NOF_CASES 16
|
||||
|
||||
typedef struct {
|
||||
cf_t h[2][2]; /* Channel estimate */
|
||||
float n; /* Noise estimation */
|
||||
float snri_1l[4]; /* SINR Approximation for 1 layer (linear) */
|
||||
float snri_2l[2]; /* SINR Approximation for 2 layers (linear) */
|
||||
uint32_t pmi[2]; /* Precoding Matrix Indicator for 1 and 2 layers */
|
||||
uint32_t ri; /* Rank indicator */
|
||||
float k; /* Condition number (κ) in dB */
|
||||
} pmi_select_test_case_gold_t;
|
||||
|
||||
static pmi_select_test_case_gold_t pmi_select_test_case_gold [PMI_SELECT_TEST_NOF_CASES] = {
|
||||
{ /* Test case 1 */
|
||||
.h = {
|
||||
{+0.626226f+0.060103f*_Complex_I, -0.233387f-0.449860f*_Complex_I},
|
||||
{+0.234558f-0.502742f*_Complex_I, +0.150990f-0.096722f*_Complex_I}
|
||||
},
|
||||
.n = 0.227713,
|
||||
.snri_1l = {2.728043f, 1.630673f, 3.226421f, 1.132295f},
|
||||
.snri_2l = {1.797660f, 1.982149f},
|
||||
.pmi = {2, 1},
|
||||
.ri = 1,
|
||||
.k = 6.4007,
|
||||
},
|
||||
{ /* Test case 2 */
|
||||
.h = {
|
||||
{+0.608899f-0.825846f*_Complex_I, +0.972208f+0.604183f*_Complex_I},
|
||||
{-0.940016f+0.978290f*_Complex_I, +0.071328f-0.866107f*_Complex_I}
|
||||
},
|
||||
.n = 0.939398,
|
||||
.snri_1l = {0.686850f, 4.591972f, 3.773925f, 1.504897f},
|
||||
.snri_2l = {2.298235f, 1.761859f},
|
||||
.pmi = {1, 0},
|
||||
.ri = 1,
|
||||
.k = 11.1305,
|
||||
},
|
||||
{ /* Test case 3 */
|
||||
.h = {
|
||||
{-0.963645f+0.770719f*_Complex_I, +0.367677f+0.798010f*_Complex_I},
|
||||
{+0.567473f+0.251875f*_Complex_I, +0.068275f-0.724262f*_Complex_I}
|
||||
},
|
||||
.n = 0.217802,
|
||||
.snri_1l = {3.209674f, 11.525338f, 11.962786f, 2.772226f},
|
||||
.snri_2l = {3.226053f, 3.526363f},
|
||||
.pmi = {2, 1},
|
||||
.ri = 1,
|
||||
.k = 15.4589,
|
||||
},
|
||||
{ /* Test case 4 */
|
||||
.h = {
|
||||
{-0.635718f+0.879322f*_Complex_I, -0.916360f-0.291089f*_Complex_I},
|
||||
{-0.786117f-0.178742f*_Complex_I, +0.232887f+0.968699f*_Complex_I}
|
||||
},
|
||||
.n = 0.945579,
|
||||
.snri_1l = {1.818313f, 2.141519f, 1.995787f, 1.964045f},
|
||||
.snri_2l = {1.965011f, 1.958537f},
|
||||
.pmi = {1, 0},
|
||||
.ri = 2,
|
||||
.k = 1.2910,
|
||||
},
|
||||
{ /* Test case 5 */
|
||||
.h = {
|
||||
{+0.353289f+0.324764f*_Complex_I, +0.976605f-0.511669f*_Complex_I},
|
||||
{+0.533663f-0.408985f*_Complex_I, -0.326601f+0.360357f*_Complex_I}
|
||||
},
|
||||
.n = 0.527847,
|
||||
.snri_1l = {1.173803f, 2.869865f, 2.273783f, 1.769885f},
|
||||
.snri_2l = {1.871430f, 1.713879f},
|
||||
.pmi = {1, 0},
|
||||
.ri = 2,
|
||||
.k = 5.5388,
|
||||
},
|
||||
{ /* Test case 6 */
|
||||
.h = {
|
||||
{-0.176813f+0.103585f*_Complex_I, +0.205276f+0.167141f*_Complex_I},
|
||||
{+0.501040f+0.023640f*_Complex_I, +0.167066f-0.834815f*_Complex_I}
|
||||
},
|
||||
.n = 0.719570,
|
||||
.snri_1l = {0.490387f, 1.022313f, 1.111245f, 0.401456f},
|
||||
.snri_2l = {0.578124f, 0.597176f},
|
||||
.pmi = {2, 1},
|
||||
.ri = 1,
|
||||
.k = 21.8808,
|
||||
},
|
||||
{ /* Test case 7 */
|
||||
.h = {
|
||||
{+0.992312f+0.773088f*_Complex_I, -0.290931f-0.090610f*_Complex_I},
|
||||
{+0.942518f-0.173145f*_Complex_I, -0.307102f-0.564536f*_Complex_I}
|
||||
},
|
||||
.n = 0.125655,
|
||||
.snri_1l = {19.459529f, 4.467420f, 18.044021f, 5.882928f},
|
||||
.snri_2l = {8.055238f, 6.832247f},
|
||||
.pmi = {0, 0},
|
||||
.ri = 1,
|
||||
.k = 9.9136,
|
||||
},
|
||||
{ /* Test case 8 */
|
||||
.h = {
|
||||
{-0.382171f-0.980395f*_Complex_I, +0.452209f+0.686427f*_Complex_I},
|
||||
{+0.565744f+0.844664f*_Complex_I, +0.387575f+0.541908f*_Complex_I}
|
||||
},
|
||||
.n = 0.042660,
|
||||
.snri_1l = {26.560881f, 49.864772f, 33.269985f, 43.155668f},
|
||||
.snri_2l = {37.201526f, 34.461078f},
|
||||
.pmi = {1, 0},
|
||||
.ri = 2,
|
||||
.k = 3.1172,
|
||||
},
|
||||
{ /* Test case 9 */
|
||||
.h = {
|
||||
{-0.243628f-0.461891f*_Complex_I, +0.408679f+0.346062f*_Complex_I},
|
||||
{+0.459026f-0.045016f*_Complex_I, -0.551446f+0.247433f*_Complex_I}
|
||||
},
|
||||
.n = 0.236445,
|
||||
.snri_1l = {1.429443f, 3.381496f, 0.227617f, 4.583322f},
|
||||
.snri_2l = {1.272903f, 2.118832f},
|
||||
.pmi = {3, 1},
|
||||
.ri = 1,
|
||||
.k = 24.1136,
|
||||
},
|
||||
{ /* Test case 10 */
|
||||
.h = {
|
||||
{-0.645752f-0.784222f*_Complex_I, +0.659287f-0.635545f*_Complex_I},
|
||||
{+0.533843f-0.801809f*_Complex_I, +0.868957f-0.020472f*_Complex_I}
|
||||
},
|
||||
.n = 0.193245,
|
||||
.snri_1l = {13.697372f, 4.693597f, 1.561737f, 16.829232f},
|
||||
.snri_2l = {2.961344f, 5.773049f},
|
||||
.pmi = {3, 1},
|
||||
.ri = 1,
|
||||
.k = 17.5194,
|
||||
},
|
||||
{ /* Test case 11 */
|
||||
.h = {
|
||||
{+0.791783f+0.544990f*_Complex_I, -0.801821f-0.376120f*_Complex_I},
|
||||
{-0.911669f-0.642035f*_Complex_I, +0.114590f-0.322089f*_Complex_I}
|
||||
},
|
||||
.n = 0.210146,
|
||||
.snri_1l = {2.340213f, 12.261749f, 5.921675f, 8.680286f},
|
||||
.snri_2l = {6.912040f, 4.520201f},
|
||||
.pmi = {1, 0},
|
||||
.ri = 2,
|
||||
.k = 7.7819,
|
||||
},
|
||||
{ /* Test case 12 */
|
||||
.h = {
|
||||
{+0.020305f-0.218290f*_Complex_I, +0.812729f-0.890767f*_Complex_I},
|
||||
{+0.257848f+0.002566f*_Complex_I, -0.796932f-0.136558f*_Complex_I}
|
||||
},
|
||||
.n = 0.997560,
|
||||
.snri_1l = {0.591218f, 1.636514f, 1.880263f, 0.347469f},
|
||||
.snri_2l = {0.869026f, 0.967991f},
|
||||
.pmi = {2, 1},
|
||||
.ri = 1,
|
||||
.k = 12.9774,
|
||||
},
|
||||
{ /* Test case 13 */
|
||||
.h = {
|
||||
{+0.623205f-0.219990f*_Complex_I, -0.028697f+0.854712f*_Complex_I},
|
||||
{+0.788896f+0.834988f*_Complex_I, -0.724907f+0.427148f*_Complex_I}
|
||||
},
|
||||
.n = 0.618337,
|
||||
.snri_1l = {3.706176f, 1.461946f, 0.479632f, 4.688490f},
|
||||
.snri_2l = {1.444336f, 2.102567f},
|
||||
.pmi = {3, 1},
|
||||
.ri = 1,
|
||||
.k = 17.0493,
|
||||
},
|
||||
{ /* Test case 14 */
|
||||
.h = {
|
||||
{-0.313424f+0.292955f*_Complex_I, +0.872055f+0.666304f*_Complex_I},
|
||||
{-0.750452f-0.203436f*_Complex_I, +0.461171f+0.499644f*_Complex_I}
|
||||
},
|
||||
.n = 0.835221,
|
||||
.snri_1l = {2.560265f, 0.379539f, 0.976562f, 1.963242f},
|
||||
.snri_2l = {1.380223f, 1.109300f},
|
||||
.pmi = {0, 0},
|
||||
.ri = 1,
|
||||
.k = 10.1729,
|
||||
},
|
||||
{ /* Test case 15 */
|
||||
.h = {
|
||||
{-0.355079f-0.339153f*_Complex_I, +0.104523f+0.238943f*_Complex_I},
|
||||
{+0.958258f-0.278727f*_Complex_I, +0.098617f+0.513019f*_Complex_I}
|
||||
},
|
||||
.n = 0.413901,
|
||||
.snri_1l = {1.633620f, 2.178855f, 0.809297f, 3.003178f},
|
||||
.snri_2l = {1.250898f, 1.512017f},
|
||||
.pmi = {3, 1},
|
||||
.ri = 1,
|
||||
.k = 10.8925,
|
||||
},
|
||||
{ /* Test case 16 */
|
||||
.h = {
|
||||
{-0.015310f+0.675606f*_Complex_I, +0.389486f+0.478144f*_Complex_I},
|
||||
{+0.945468f+0.908349f*_Complex_I, -0.344490f-0.936155f*_Complex_I}
|
||||
},
|
||||
.n = 0.356869,
|
||||
.snri_1l = {5.024121f, 4.926495f, 7.364348f, 2.586268f},
|
||||
.snri_2l = {3.165416f, 3.851590f},
|
||||
.pmi = {2, 1},
|
||||
.ri = 2,
|
||||
.k = 7.7799,
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* PMI_SELECT_TEST_H */
|
|
@ -78,9 +78,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols/nof_layers);
|
||||
}
|
||||
|
||||
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports/nof_layers);
|
||||
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports);
|
||||
for (int i=0;i<nof_tx_ports;i++) {
|
||||
y[i] = &output[i*nof_symbols/nof_layers];
|
||||
y[i] = &output[i*nof_symbols];
|
||||
}
|
||||
|
||||
char *txscheme = "Port0";
|
||||
|
@ -102,13 +102,30 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
}
|
||||
int symbols_layers[SRSLTE_MAX_LAYERS];
|
||||
for (int i=0;i<nof_layers;i++) {
|
||||
symbols_layers[i] = nof_symbols/nof_layers;
|
||||
symbols_layers[i] = nof_symbols;
|
||||
}
|
||||
srslte_layermap_type(d, x, nof_codewords, nof_layers, symbols_layers, type);
|
||||
srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols/nof_layers, type);
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports);
|
||||
switch (type) {
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports);
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
default:
|
||||
mexutils_write_cf(output, &plhs[0], (uint32_t) nof_symbols, nof_tx_ports);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nlhs >= 2) {
|
||||
mexutils_write_cf(x[0], &plhs[1], nof_symbols / nof_layers, 1);
|
||||
}
|
||||
if (nlhs >= 3) {
|
||||
mexutils_write_cf(x[1], &plhs[2], nof_symbols / nof_layers, 1);
|
||||
}
|
||||
|
||||
if (input) {
|
||||
|
|
|
@ -34,29 +34,41 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
#include "srslte/phy/channel/ch_awgn.h"
|
||||
|
||||
#define MSE_THRESHOLD 0.00001
|
||||
#define MSE_THRESHOLD 0.0005
|
||||
|
||||
int nof_symbols = 1000;
|
||||
int nof_layers = 1, nof_ports = 1;
|
||||
uint32_t codebook_idx = 0;
|
||||
int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1;
|
||||
char *mimo_type_name = NULL;
|
||||
char decoder_type_name [16] = "zf";
|
||||
float snr_db = 100.0f;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf(
|
||||
"Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n",
|
||||
prog);
|
||||
"Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n"
|
||||
" -r [nof_rx_ports]\n", prog);
|
||||
printf("\t-n num_symbols [Default %d]\n", nof_symbols);
|
||||
printf("\t-c codebook_idx [Default %d]\n", codebook_idx);
|
||||
printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db);
|
||||
printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name);
|
||||
printf("\n");
|
||||
printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name);
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "mpln")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "mplnrcds")) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
nof_symbols = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
nof_ports = atoi(argv[optind]);
|
||||
nof_tx_ports = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
nof_rx_ports = atoi(argv[optind]);
|
||||
break;
|
||||
case 'l':
|
||||
nof_layers = atoi(argv[optind]);
|
||||
|
@ -64,6 +76,15 @@ void parse_args(int argc, char **argv) {
|
|||
case 'm':
|
||||
mimo_type_name = argv[optind];
|
||||
break;
|
||||
case 'c':
|
||||
codebook_idx = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
strncpy(decoder_type_name, argv[optind], 16);
|
||||
break;
|
||||
case 's':
|
||||
snr_db = (float) atof(argv[optind]);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
|
@ -75,129 +96,236 @@ void parse_args(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
void populate_channel_cdd(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t n) {
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < nof_tx_ports; i++) {
|
||||
for (j = 0; j < nof_rx_ports; j++) {
|
||||
for (k = 0; k < n; k++) {
|
||||
h[i][j][k] = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void populate_channel_diversity(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t n) {
|
||||
int i, j, k, l;
|
||||
|
||||
for (i = 0; i < nof_tx_ports; i++) {
|
||||
for (j = 0; j < nof_rx_ports; j++) {
|
||||
for (k = 0; k < n / nof_layers; k++) {
|
||||
cf_t hsymb = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I;
|
||||
for (l = 0; l < nof_layers; l++) {
|
||||
// assume the channel is the same for all symbols
|
||||
h[i][j][k * nof_layers + l] = hsymb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void populate_channel_single(cf_t *h) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nof_re; i++) {
|
||||
h[i] = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I;
|
||||
}
|
||||
}
|
||||
|
||||
void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) {
|
||||
switch (type) {
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
populate_channel_cdd(h, (uint32_t) nof_re);
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
populate_channel_diversity(h, (uint32_t) nof_re);
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
default:
|
||||
populate_channel_single(h[0][0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) {
|
||||
int i;
|
||||
float std_dev = powf(10, - (snr + 3.0f) / 20.0f);
|
||||
|
||||
for (i = 0; i < nof_rx_ports; i++) {
|
||||
srslte_ch_awgn_c(y[i], y[i], std_dev, n);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i, j;
|
||||
int i, j, k, nof_errors = 0, ret = SRSLTE_SUCCESS;
|
||||
float mse;
|
||||
cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS],
|
||||
cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
*xr[SRSLTE_MAX_LAYERS];
|
||||
srslte_mimo_type_t type;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (nof_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) {
|
||||
/* Check input ranges */
|
||||
if (nof_tx_ports > SRSLTE_MAX_PORTS || nof_rx_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) {
|
||||
fprintf(stderr, "Invalid number of layers or ports\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Parse MIMO Type */
|
||||
if (srslte_str2mimotype(mimo_type_name, &type)) {
|
||||
fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Check scenario conditions are OK */
|
||||
switch (type) {
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
nof_re = nof_layers*nof_symbols;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
nof_re = nof_symbols;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
nof_re = nof_symbols*nof_tx_ports/nof_layers;
|
||||
if (nof_rx_ports != 2 || nof_tx_ports != 2) {
|
||||
fprintf(stderr, "CDD nof_tx_ports=%d nof_rx_ports=%d is not currently supported\n", nof_tx_ports, nof_rx_ports);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
nof_re = nof_symbols*nof_layers;
|
||||
}
|
||||
|
||||
/* Allocate x and xr (received symbols) in memory for each layer */
|
||||
for (i = 0; i < nof_layers; i++) {
|
||||
/* Source data */
|
||||
x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
|
||||
if (!x[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Sink data */
|
||||
xr[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
|
||||
if (!xr[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < nof_ports; i++) {
|
||||
y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers);
|
||||
// TODO: The number of symbols per port is different in spatial multiplexing.
|
||||
|
||||
/* Allocate y in memory for tx each port */
|
||||
for (i = 0; i < nof_tx_ports; i++) {
|
||||
y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
|
||||
if (!y[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
exit(-1);
|
||||
}
|
||||
h[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers);
|
||||
if (!h[i]) {
|
||||
}
|
||||
|
||||
/* Allocate h in memory for each cross channel and layer */
|
||||
for (i = 0; i < nof_tx_ports; i++) {
|
||||
for (j = 0; j < nof_rx_ports; j++) {
|
||||
h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
|
||||
if (!h[i][j]) {
|
||||
perror("srslte_vec_malloc");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate r */
|
||||
for (i = 0; i < nof_rx_ports; i++) {
|
||||
r[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
|
||||
if (!r[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* only 1 receiver antenna supported now */
|
||||
r[0] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers);
|
||||
if (!r[0]) {
|
||||
perror("srslte_vec_malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* generate random data */
|
||||
/* Generate source random data */
|
||||
for (i = 0; i < nof_layers; i++) {
|
||||
for (j = 0; j < nof_symbols; j++) {
|
||||
x[i][j] = (2*(rand()%2)-1+(2*(rand()%2)-1)*_Complex_I)/sqrt(2);
|
||||
x[i][j] = (2 * (rand() % 2) - 1 + (2 * (rand() % 2) - 1) * _Complex_I) / sqrt(2);
|
||||
}
|
||||
}
|
||||
|
||||
/* precoding */
|
||||
if (srslte_precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) {
|
||||
|
||||
/* Execute Precoding (Tx) */
|
||||
if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, type) < 0) {
|
||||
fprintf(stderr, "Error layer mapper encoder\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* generate channel */
|
||||
for (i = 0; i < nof_ports; i++) {
|
||||
for (j = 0; j < nof_symbols; j++) {
|
||||
h[i][nof_layers*j] = (float) rand()/RAND_MAX+((float) rand()/RAND_MAX)*_Complex_I;
|
||||
// assume the channel is time-invariant in nlayer consecutive symbols
|
||||
for (int k=0;k<nof_layers;k++) {
|
||||
h[i][nof_layers*j+k] = h[i][nof_layers*j];
|
||||
populate_channel(type, h);
|
||||
|
||||
/* pass signal through channel
|
||||
(we are in the frequency domain so it's a multiplication) */
|
||||
for (i = 0; i < nof_rx_ports; i++) {
|
||||
for (k = 0; k < nof_re; k++) {
|
||||
r[i][k] = (cf_t) (0.0 + 0.0 * _Complex_I);
|
||||
for (j = 0; j < nof_tx_ports; j++) {
|
||||
r[i][k] += y[j][k] * h[j][i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* pass signal through channel
|
||||
(we are in the frequency domain so it's a multiplication) */
|
||||
/* there's only one receiver antenna, signals from different transmitter
|
||||
* ports are simply combined at the receiver
|
||||
*/
|
||||
for (j = 0; j < nof_symbols * nof_layers; j++) {
|
||||
r[0][j] = 0;
|
||||
for (i = 0; i < nof_ports; i++) {
|
||||
r[0][j] += y[i][j] * h[i][j];
|
||||
}
|
||||
awgn(r, (uint32_t) nof_re, snr_db);
|
||||
|
||||
/* If CDD or Spatial muliplex choose decoder */
|
||||
if (strncmp(decoder_type_name, "zf", 16) == 0) {
|
||||
srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_ZF);
|
||||
} else if (strncmp(decoder_type_name, "mmse", 16) == 0) {
|
||||
srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_MMSE);
|
||||
} else {
|
||||
ret = SRSLTE_ERROR;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* predecoding / equalization */
|
||||
struct timeval t[3];
|
||||
gettimeofday(&t[1], NULL);
|
||||
if (srslte_predecoding_type(r[0], h, xr, nof_ports, nof_layers,
|
||||
nof_symbols * nof_layers, type, 0) < 0) {
|
||||
fprintf(stderr, "Error layer mapper encoder\n");
|
||||
exit(-1);
|
||||
}
|
||||
srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers,
|
||||
codebook_idx, nof_re, type, powf(10, -snr_db/10));
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
printf("Execution Time: %ld us\n", t[0].tv_usec);
|
||||
|
||||
|
||||
/* check errors */
|
||||
mse = 0;
|
||||
for (i = 0; i < nof_layers; i++) {
|
||||
for (j = 0; j < nof_symbols; j++) {
|
||||
mse += cabsf(xr[i][j] - x[i][j]);
|
||||
|
||||
if ((crealf(xr[i][j]) > 0) != (crealf(x[i][j]) > 0)) {
|
||||
nof_errors ++;
|
||||
}
|
||||
if ((cimagf(xr[i][j]) > 0) != (cimagf(x[i][j]) > 0)) {
|
||||
nof_errors ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("MSE: %f\n", mse/ nof_layers / nof_symbols );
|
||||
printf("SNR: %5.1fdB;\tExecution time: %5ldus;\tMSE: %.6f;\tBER: %.6f\n", snr_db, t[0].tv_usec,
|
||||
mse / nof_layers / nof_symbols, (float) nof_errors / (4.0f * nof_re));
|
||||
if (mse / nof_layers / nof_symbols > MSE_THRESHOLD) {
|
||||
exit(-1);
|
||||
ret = SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
quit:
|
||||
/* Free all data */
|
||||
for (i = 0; i < nof_layers; i++) {
|
||||
free(x[i]);
|
||||
free(xr[i]);
|
||||
}
|
||||
for (i = 0; i < nof_ports; i++) {
|
||||
free(y[i]);
|
||||
free(h[i]);
|
||||
|
||||
for (i = 0; i < nof_rx_ports; i++) {
|
||||
free(r[i]);
|
||||
}
|
||||
|
||||
free(r[0]);
|
||||
|
||||
printf("Ok\n");
|
||||
exit(0);
|
||||
for (i = 0; i < nof_rx_ports; i++) {
|
||||
for (j = 0; j < nof_tx_ports; j++) {
|
||||
free(h[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
|
|
@ -35,8 +35,10 @@
|
|||
#define HEST prhs[1]
|
||||
#define NEST prhs[2]
|
||||
#define NLAYERS prhs[3]
|
||||
#define TXSCHEME prhs[4]
|
||||
#define NOF_INPUTS 5
|
||||
#define NCW prhs[4]
|
||||
#define TXSCHEME prhs[5]
|
||||
#define CODEBOOK prhs[6]
|
||||
#define NOF_INPUTS 7
|
||||
|
||||
|
||||
void help()
|
||||
|
@ -48,118 +50,159 @@ void help()
|
|||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
const mwSize *dims = mxGetDimensions(INPUT);
|
||||
mwSize ndims;
|
||||
cf_t *input = NULL;
|
||||
cf_t *hest = NULL;
|
||||
cf_t *output = NULL;
|
||||
uint32_t nof_symbols = 0;
|
||||
uint32_t nof_rx_ants = 1;
|
||||
uint32_t nof_layers;
|
||||
uint32_t nof_tx_ports = 1;
|
||||
uint32_t nof_codewords = 1;
|
||||
uint32_t codebook_idx = 0;
|
||||
float noise_estimate = 0;
|
||||
cf_t *x[SRSLTE_MAX_LAYERS];
|
||||
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
|
||||
cf_t *y[SRSLTE_MAX_PORTS];
|
||||
int symbols_layers[SRSLTE_MAX_LAYERS];
|
||||
int i, j;
|
||||
srslte_mimo_type_t type;
|
||||
|
||||
/* Print help if number of inputs does not match with expected */
|
||||
if (nrhs < NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read input symbols
|
||||
/* Read input symbols */
|
||||
if (mexutils_read_cf(INPUT, &input) < 0) {
|
||||
mexErrMsgTxt("Error reading input\n");
|
||||
return;
|
||||
}
|
||||
uint32_t nof_layers = mxGetScalar(NLAYERS);
|
||||
uint32_t nof_tx_ports = 1;
|
||||
uint32_t nof_codewords = 1;
|
||||
|
||||
uint32_t nof_rx_ants = 1;
|
||||
const mwSize *dims = mxGetDimensions(INPUT);
|
||||
mwSize ndims = mxGetNumberOfDimensions(INPUT);
|
||||
nof_symbols = dims[0];
|
||||
|
||||
/* Read number of layers */
|
||||
nof_layers = (uint32_t) mxGetScalar(NLAYERS);
|
||||
|
||||
/* Read number of codewords */
|
||||
nof_codewords = (uint32_t) mxGetScalar(NCW);
|
||||
|
||||
if (nof_layers > SRSLTE_MAX_LAYERS) {
|
||||
mexErrMsgTxt("Too many layers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read number of symbols and Rx antennas */
|
||||
ndims = mxGetNumberOfDimensions(INPUT);
|
||||
nof_symbols = (uint32_t) dims[0];
|
||||
|
||||
if (ndims >= 2) {
|
||||
nof_rx_ants = dims[1];
|
||||
nof_rx_ants = (uint32_t) dims[1];
|
||||
}
|
||||
|
||||
// Read channel estimates
|
||||
/* Read channel estimates */
|
||||
if (mexutils_read_cf(HEST, &hest) < 0) {
|
||||
mexErrMsgTxt("Error reading hest\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get number of tx ports */
|
||||
dims = mxGetDimensions(HEST);
|
||||
ndims = mxGetNumberOfDimensions(HEST);
|
||||
|
||||
if (ndims == 3) {
|
||||
nof_tx_ports = dims[2];
|
||||
nof_tx_ports = (uint32_t) dims[2];
|
||||
}
|
||||
|
||||
mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_rx_ants, nof_layers, nof_symbols);
|
||||
|
||||
// Read noise estimate
|
||||
float noise_estimate = 0;
|
||||
/* Print parameters trace */
|
||||
mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_codewords=%d, codebook_idx=%d, nof_symbols=%d\n",
|
||||
nof_tx_ports, nof_rx_ants, nof_layers, nof_codewords, codebook_idx, nof_symbols);
|
||||
|
||||
/* Read noise estimate */
|
||||
if (nrhs >= NOF_INPUTS) {
|
||||
noise_estimate = mxGetScalar(NEST);
|
||||
noise_estimate = (float) mxGetScalar(NEST);
|
||||
}
|
||||
|
||||
cf_t *x[SRSLTE_MAX_LAYERS];
|
||||
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
|
||||
cf_t *y[SRSLTE_MAX_PORTS];
|
||||
|
||||
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
|
||||
/* Initialise x, h & y pointers */
|
||||
for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
|
||||
x[i] = NULL;
|
||||
}
|
||||
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
|
||||
for (int j=0;j<SRSLTE_MAX_PORTS;j++) {
|
||||
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
|
||||
for (j=0;j<SRSLTE_MAX_PORTS;j++) {
|
||||
h[i][j] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory */
|
||||
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols);
|
||||
for (int i = 0; i < nof_tx_ports; i++) {
|
||||
x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols);
|
||||
for (int j=0;j<nof_rx_ants;j++) {
|
||||
h[i][j] = &hest[i*nof_symbols*nof_rx_ants + j*nof_symbols];
|
||||
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
|
||||
y[i] = NULL;
|
||||
}
|
||||
|
||||
/* Allocate memory for ouput */
|
||||
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_layers);
|
||||
|
||||
/* Allocate memory for intermediate data */
|
||||
for (i = 0; i < nof_tx_ports; i++) {
|
||||
x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols*nof_layers);
|
||||
}
|
||||
|
||||
/* Allocate memory for channel estimate */
|
||||
for (i = 0; i < nof_tx_ports; i++) {
|
||||
for (j=0; j<nof_rx_ants; j++) {
|
||||
h[i][j] = &hest[(i*nof_rx_ants + j)*nof_symbols];
|
||||
}
|
||||
}
|
||||
|
||||
for (int j=0;j<nof_rx_ants;j++) {
|
||||
|
||||
/* Allocate memory for input */
|
||||
for (j = 0; j < nof_rx_ants; j++) {
|
||||
y[j] = &input[j*nof_symbols];
|
||||
}
|
||||
|
||||
char *txscheme = "Port0";
|
||||
|
||||
/* Parse Tx scheme */
|
||||
char txscheme[32] = "Port0";
|
||||
if (nrhs >= NOF_INPUTS) {
|
||||
txscheme = mxArrayToString(TXSCHEME);
|
||||
}
|
||||
srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
if (!strcmp(txscheme, "Port0")) {
|
||||
type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
} else if (!strcmp(txscheme, "TxDiversity")) {
|
||||
type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
} else if (!strcmp(txscheme, "CDD")) {
|
||||
type = SRSLTE_MIMO_TYPE_CDD;
|
||||
} else if (!strcmp(txscheme, "SpatialMux")) {
|
||||
type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
} else {
|
||||
mxGetString_700(TXSCHEME, txscheme, 32);
|
||||
}
|
||||
|
||||
codebook_idx = (uint32_t) mxGetScalar(CODEBOOK);
|
||||
|
||||
if (srslte_str2mimotype(txscheme, &type)) {
|
||||
mexPrintf("Unsupported TxScheme=%s\n", txscheme);
|
||||
return;
|
||||
}
|
||||
int symbols_layers[SRSLTE_MAX_LAYERS];
|
||||
for (int i=0;i<nof_layers;i++) {
|
||||
|
||||
/* Populate symbols in layers */
|
||||
for (i = 0; i < nof_layers; i++) {
|
||||
symbols_layers[i] = nof_symbols;
|
||||
}
|
||||
cf_t *d[SRSLTE_MAX_LAYERS];
|
||||
d[0] = output;
|
||||
srslte_predecoding_type_multi(y, h, x, nof_rx_ants, nof_tx_ports, nof_layers, nof_symbols/nof_layers, type, noise_estimate);
|
||||
|
||||
/* Set output pointer */
|
||||
cf_t *d[SRSLTE_MAX_CODEWORDS];
|
||||
for (i = 0; i<nof_codewords; i++) {
|
||||
d[i] = &output[i*nof_symbols*nof_layers/nof_codewords];
|
||||
}
|
||||
|
||||
/* Pre-decode */
|
||||
srslte_predecoding_type_multi(y, h, x, nof_rx_ants, nof_tx_ports, nof_layers, codebook_idx, nof_symbols, type,
|
||||
noise_estimate);
|
||||
|
||||
/* Layer de-mapper */
|
||||
srslte_layerdemap_type(x, d, nof_layers, nof_codewords, nof_symbols, symbols_layers, type);
|
||||
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_cf(output, &plhs[0], nof_symbols, 1);
|
||||
/* Write output */
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_cf(output, &plhs[0], nof_symbols, nof_codewords);
|
||||
}
|
||||
|
||||
|
||||
/* Free memory */
|
||||
if (input) {
|
||||
free(input);
|
||||
}
|
||||
if (hest) {
|
||||
free(hest);
|
||||
}
|
||||
if (output) {
|
||||
free(output);
|
||||
}
|
||||
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
|
||||
for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
|
||||
if (x[i]) {
|
||||
free(x[i]);
|
||||
}
|
||||
|
|
|
@ -159,46 +159,54 @@ int srslte_cqi_size(srslte_cqi_value_t *value) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) {
|
||||
if (I_cqi_pmi <= 1) {
|
||||
*N_p = 2;
|
||||
*N_offset = I_cqi_pmi;
|
||||
} else if (I_cqi_pmi <= 6) {
|
||||
*N_p = 5;
|
||||
*N_offset = I_cqi_pmi - 2;
|
||||
} else if (I_cqi_pmi <= 16) {
|
||||
*N_p = 10;
|
||||
*N_offset = I_cqi_pmi - 7;
|
||||
} else if (I_cqi_pmi <= 36) {
|
||||
*N_p = 20;
|
||||
*N_offset = I_cqi_pmi - 17;
|
||||
} else if (I_cqi_pmi <= 76) {
|
||||
*N_p = 40;
|
||||
*N_offset = I_cqi_pmi - 37;
|
||||
} else if (I_cqi_pmi <= 156) {
|
||||
*N_p = 80;
|
||||
*N_offset = I_cqi_pmi - 77;
|
||||
} else if (I_cqi_pmi <= 316) {
|
||||
*N_p = 160;
|
||||
*N_offset = I_cqi_pmi - 157;
|
||||
} else if (I_cqi_pmi == 317) {
|
||||
return false;
|
||||
} else if (I_cqi_pmi <= 349) {
|
||||
*N_p = 32;
|
||||
*N_offset = I_cqi_pmi - 318;
|
||||
} else if (I_cqi_pmi <= 413) {
|
||||
*N_p = 64;
|
||||
*N_offset = I_cqi_pmi - 350;
|
||||
} else if (I_cqi_pmi <= 541) {
|
||||
*N_p = 128;
|
||||
*N_offset = I_cqi_pmi - 414;
|
||||
} else if (I_cqi_pmi <= 1023) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) {
|
||||
|
||||
uint32_t N_p = 0;
|
||||
uint32_t N_offset = 0;
|
||||
|
||||
if (I_cqi_pmi <= 1) {
|
||||
N_p = 2;
|
||||
N_offset = I_cqi_pmi;
|
||||
} else if (I_cqi_pmi <= 6) {
|
||||
N_p = 5;
|
||||
N_offset = I_cqi_pmi - 2;
|
||||
} else if (I_cqi_pmi <= 16) {
|
||||
N_p = 10;
|
||||
N_offset = I_cqi_pmi - 7;
|
||||
} else if (I_cqi_pmi <= 36) {
|
||||
N_p = 20;
|
||||
N_offset = I_cqi_pmi - 17;
|
||||
} else if (I_cqi_pmi <= 76) {
|
||||
N_p = 40;
|
||||
N_offset = I_cqi_pmi - 37;
|
||||
} else if (I_cqi_pmi <= 156) {
|
||||
N_p = 80;
|
||||
N_offset = I_cqi_pmi - 77;
|
||||
} else if (I_cqi_pmi <= 316) {
|
||||
N_p = 160;
|
||||
N_offset = I_cqi_pmi - 157;
|
||||
} else if (I_cqi_pmi == 317) {
|
||||
return false;
|
||||
} else if (I_cqi_pmi <= 349) {
|
||||
N_p = 32;
|
||||
N_offset = I_cqi_pmi - 318;
|
||||
} else if (I_cqi_pmi <= 413) {
|
||||
N_p = 64;
|
||||
N_offset = I_cqi_pmi - 350;
|
||||
} else if (I_cqi_pmi <= 541) {
|
||||
N_p = 128;
|
||||
N_offset = I_cqi_pmi - 414;
|
||||
} else if (I_cqi_pmi <= 1023) {
|
||||
return false;
|
||||
|
||||
if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (N_p) {
|
||||
if ((tti-N_offset)%N_p == 0) {
|
||||
return true;
|
||||
|
@ -207,6 +215,47 @@ bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool srslte_ri_send(uint32_t I_cqi_pmi, uint32_t I_ri, uint32_t tti) {
|
||||
|
||||
uint32_t M_ri = 0;
|
||||
uint32_t N_offset_ri = 0;
|
||||
uint32_t N_p = 0;
|
||||
uint32_t N_offset_p = 0;
|
||||
|
||||
if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset_p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (I_ri <= 160) {
|
||||
M_ri = 1;
|
||||
N_offset_ri = I_ri;
|
||||
} else if (I_ri <= 161) {
|
||||
M_ri = 2;
|
||||
N_offset_ri = I_ri - 161;
|
||||
} else if (I_ri <= 322) {
|
||||
M_ri = 4;
|
||||
N_offset_ri = I_ri - 322;
|
||||
} else if (I_ri <= 483) {
|
||||
M_ri = 8;
|
||||
N_offset_ri = I_ri - 483;
|
||||
} else if (I_ri <= 644) {
|
||||
M_ri = 16;
|
||||
N_offset_ri = I_ri - 644;
|
||||
} else if (I_ri <= 805) {
|
||||
M_ri = 32;
|
||||
N_offset_ri = I_ri - 805;
|
||||
} else if (I_ri <= 966) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (M_ri) {
|
||||
if ((tti - N_offset_p + N_offset_ri) % (N_p * M_ri) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// CQI-to-Spectral Efficiency: 36.213 Table 7.2.3-1 */
|
||||
static float cqi_to_coderate[16] = {0, 0.1523, 0.2344, 0.3770, 0.6016, 0.8770, 1.1758, 1.4766, 1.9141, 2.4063, 2.7305, 3.3223, 3.9023, 4.5234, 5.1152, 5.5547};
|
||||
|
|
|
@ -1051,6 +1051,16 @@ int dci_format2AB_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t
|
|||
} else {
|
||||
*y++ = data->tb_cw_swap;
|
||||
}
|
||||
|
||||
/* Force MCS_idx and RV_idx in function of block enable according to 7.1.7 of 36.213 */
|
||||
if (!data->tb_en[0]) {
|
||||
data->mcs_idx = 0;
|
||||
data->rv_idx= 1;
|
||||
}
|
||||
if (!data->tb_en[1]) {
|
||||
data->mcs_idx_1 = 0;
|
||||
data->rv_idx_1 = 1;
|
||||
}
|
||||
|
||||
/* pack TB1 */
|
||||
srslte_bit_unpack(data->mcs_idx, &y, 5);
|
||||
|
|
|
@ -65,7 +65,19 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell
|
|||
return srslte_pdcch_init_multi(q, regs, cell, 1);
|
||||
}
|
||||
|
||||
int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas)
|
||||
int srslte_pdcch_init_tx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) {
|
||||
return srslte_pdcch_init_txrx(q, regs, cell, 1, false);
|
||||
}
|
||||
|
||||
int srslte_pdcch_init_rx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) {
|
||||
return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true);
|
||||
}
|
||||
|
||||
int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) {
|
||||
return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true);
|
||||
}
|
||||
|
||||
int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas, bool isReceiver)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
|
@ -122,19 +134,25 @@ int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_
|
|||
goto clean;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
for (int j=0;j<q->nof_rx_antennas;j++) {
|
||||
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->ce[i][j]) {
|
||||
goto clean;
|
||||
}
|
||||
if (isReceiver) {
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
for (int j = 0; j < q->nof_rx_antennas; j++) {
|
||||
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->ce[i][j]) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->x[i]) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
for (int j=0;j<q->nof_rx_antennas;j++) {
|
||||
|
||||
for (int j = 0; j < ((isReceiver) ? q->nof_rx_antennas : cell.nof_ports); j++) {
|
||||
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->symbols[j]) {
|
||||
goto clean;
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <srslte/phy/phch/pdsch.h>
|
||||
|
||||
#include "prb_dl.h"
|
||||
#include "srslte/phy/phch/pdsch.h"
|
||||
|
@ -198,20 +197,15 @@ int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols,
|
|||
return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false);
|
||||
}
|
||||
|
||||
int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell)
|
||||
{
|
||||
return srslte_pdsch_init_multi(q, cell, 1);
|
||||
}
|
||||
|
||||
/** Initializes the PDCCH transmitter and receiver */
|
||||
int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_rx_antennas)
|
||||
/** Initializes the PDCCH transmitter or receiver */
|
||||
int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas, bool is_receiver)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
int i;
|
||||
|
||||
if (q != NULL &&
|
||||
srslte_cell_isvalid(&cell) &&
|
||||
nof_rx_antennas <= SRSLTE_MAX_PORTS)
|
||||
nof_antennas <= SRSLTE_MAX_PORTS)
|
||||
{
|
||||
|
||||
bzero(q, sizeof(srslte_pdsch_t));
|
||||
|
@ -219,8 +213,10 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_
|
|||
|
||||
q->cell = cell;
|
||||
q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp);
|
||||
q->nof_rx_antennas = nof_rx_antennas;
|
||||
|
||||
if (is_receiver) {
|
||||
q->nof_rx_antennas = nof_antennas;
|
||||
}
|
||||
|
||||
INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
|
||||
q->cell.nof_prb, q->max_re);
|
||||
|
||||
|
@ -230,29 +226,41 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_
|
|||
}
|
||||
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) {
|
||||
|
||||
if (srslte_sch_init(&q->dl_sch)) {
|
||||
ERROR("Initiating DL SCH");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
// Allocate int16_t for reception (LLRs)
|
||||
q->e[i] = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
|
||||
if (!q->e[i]) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->d[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
|
||||
if (!q->d[i]) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
/* Layer mapped symbols memory allocation */
|
||||
for (i = 0; i < q->cell.nof_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;
|
||||
}
|
||||
|
||||
/* If it is the receiver side, allocate estimated channel */
|
||||
if (is_receiver) {
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,30 +271,48 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_
|
|||
}
|
||||
}
|
||||
|
||||
/* Allocate User memory (all zeros) */
|
||||
q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI);
|
||||
if (!q->users) {
|
||||
perror("malloc");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
clean:
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
|
||||
clean:
|
||||
if (ret == SRSLTE_ERROR) {
|
||||
srslte_pdsch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srslte_pdsch_init_tx(srslte_pdsch_t *q, srslte_cell_t cell) {
|
||||
return srslte_pdsch_init(q, cell, 0, false);
|
||||
}
|
||||
|
||||
int srslte_pdsch_init_rx(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas) {
|
||||
return srslte_pdsch_init(q, cell, nof_antennas, true);
|
||||
}
|
||||
|
||||
void srslte_pdsch_free(srslte_pdsch_t *q) {
|
||||
int i;
|
||||
|
||||
if (q->e) {
|
||||
free(q->e);
|
||||
}
|
||||
if (q->d) {
|
||||
free(q->d);
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
|
||||
if (q->e[i]) {
|
||||
free(q->e[i]);
|
||||
}
|
||||
|
||||
if (q->d[i]) {
|
||||
free(q->d[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free sch objects */
|
||||
srslte_sch_free(&q->dl_sch);
|
||||
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
if (q->x[i]) {
|
||||
free(q->x[i]);
|
||||
|
@ -297,7 +323,7 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (int j=0;j<q->nof_rx_antennas;j++) {
|
||||
for (int j=0;j<SRSLTE_MAX_PORTS;j++) {
|
||||
if (q->symbols[j]) {
|
||||
free(q->symbols[j]);
|
||||
}
|
||||
|
@ -314,48 +340,24 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
|
|||
srslte_modem_table_free(&q->mod[i]);
|
||||
}
|
||||
|
||||
srslte_sch_free(&q->dl_sch);
|
||||
|
||||
bzero(q, sizeof(srslte_pdsch_t));
|
||||
|
||||
}
|
||||
|
||||
/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg.
|
||||
* If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant
|
||||
*/
|
||||
int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx)
|
||||
{
|
||||
if (cfg) {
|
||||
if (grant) {
|
||||
memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t));
|
||||
}
|
||||
if (srslte_cbsegm(&cfg->cb_segm, cfg->grant.mcs.tbs)) {
|
||||
fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs.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 = rvidx;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
} else {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while
|
||||
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while
|
||||
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
|
||||
*/
|
||||
int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
|
||||
uint32_t i;
|
||||
uint32_t i, j;
|
||||
if (!q->users[rnti]) {
|
||||
q->users[rnti] = calloc(1, sizeof(srslte_pdsch_user_t));
|
||||
if (q->users[rnti]) {
|
||||
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
|
||||
if (srslte_sequence_pdsch(&q->users[rnti]->seq[i], rnti, 0, 2 * i, q->cell.id,
|
||||
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
|
||||
return SRSLTE_ERROR;
|
||||
for (j = 0; j < SRSLTE_MAX_CODEWORDS; j++) {
|
||||
if (srslte_sequence_pdsch(&q->users[rnti]->seq[j][i], rnti, j, 2 * i, q->cell.id,
|
||||
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
|
||||
ERROR("Generating scrambling sequence");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
q->users[rnti]->sequence_generated = true;
|
||||
|
@ -368,206 +370,391 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
|
|||
{
|
||||
if (q->users[rnti]) {
|
||||
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
|
||||
srslte_sequence_free(&q->users[rnti]->seq[i]);
|
||||
for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) {
|
||||
srslte_sequence_free(&q->users[rnti]->seq[j][i]);
|
||||
}
|
||||
}
|
||||
free(q->users[rnti]);
|
||||
q->users[rnti] = NULL;
|
||||
q->users[rnti] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_pdsch_decode(srslte_pdsch_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 rnti, uint8_t *data)
|
||||
static void pdsch_decode_debug(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg,
|
||||
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS])
|
||||
{
|
||||
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_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, data);
|
||||
}
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
char filename[FILENAME_MAX];
|
||||
for (int j = 0; j < q->nof_rx_antennas; j++) {
|
||||
if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) {
|
||||
ERROR("Generating file name");
|
||||
break;
|
||||
}
|
||||
DEBUG("SAVED FILE %s: received subframe symbols\n", filename);
|
||||
srslte_vec_save_file(filename, sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
|
||||
|
||||
/** Decodes the PDSCH from the received symbols
|
||||
*/
|
||||
int srslte_pdsch_decode_multi(srslte_pdsch_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 rnti, 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 PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d\n",
|
||||
cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re,
|
||||
cfg->nbits.nof_bits, cfg->rv, cfg->grant.nof_prb);
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
x[i] = q->x[i];
|
||||
for (int i = 0; i < q->cell.nof_ports; i++) {
|
||||
if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) {
|
||||
ERROR("Generating file name");
|
||||
break;
|
||||
}
|
||||
DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i);
|
||||
srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
|
||||
}
|
||||
}
|
||||
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_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
|
||||
if (n != cfg->nbits.nof_re) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n);
|
||||
DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0);
|
||||
srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits[0].nof_re*sizeof(cf_t));
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg.
|
||||
* If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant
|
||||
*/
|
||||
int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi,
|
||||
uint32_t sf_idx, int rvidx) {
|
||||
int _rvids[SRSLTE_MAX_CODEWORDS] = {1};
|
||||
_rvids[0] = rvidx;
|
||||
|
||||
return srslte_pdsch_cfg_mimo(cfg, cell, grant, cfi, sf_idx, _rvids, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0);
|
||||
}
|
||||
|
||||
/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg.
|
||||
* If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant
|
||||
*/
|
||||
int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi,
|
||||
uint32_t sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type,
|
||||
uint32_t pmi) {
|
||||
if (cfg) {
|
||||
if (grant) {
|
||||
memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t));
|
||||
}
|
||||
|
||||
for (int i = 0; i < grant->nof_tb; i++) {
|
||||
if (srslte_cbsegm(&cfg->cb_segm[i], (uint32_t) cfg->grant.mcs[i].tbs)) {
|
||||
fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[i].tbs);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
|
||||
if (n != cfg->nbits.nof_re) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n);
|
||||
}
|
||||
srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits);
|
||||
|
||||
cfg->sf_idx = sf_idx;
|
||||
memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS);
|
||||
cfg->mimo_type = mimo_type;
|
||||
|
||||
/* Check and configure PDSCH transmission modes */
|
||||
switch(mimo_type) {
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
if (grant->nof_tb != 1) {
|
||||
ERROR("Number of transport blocks is not supported for single transmission mode.");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: only diversity is supported */
|
||||
if (q->cell.nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate);
|
||||
} else {
|
||||
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nbits.nof_re);
|
||||
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0);
|
||||
srslte_vec_save_file("subframe.dat", sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
|
||||
DEBUG("SAVED FILE hest0.dat and hest1.dat: channel estimates for port 0 and port 1\n",0);
|
||||
srslte_vec_save_file("hest0.dat", ce[0][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
|
||||
if (q->cell.nof_ports > 1) {
|
||||
srslte_vec_save_file("hest1.dat", ce[1][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
|
||||
}
|
||||
DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0);
|
||||
srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.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 the LLRs normalization
|
||||
*/
|
||||
srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re);
|
||||
|
||||
/* descramble */
|
||||
if (q->users[rnti] && q->users[rnti]->sequence_generated) {
|
||||
srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits);
|
||||
} else {
|
||||
srslte_sequence_t seq;
|
||||
if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits);
|
||||
srslte_sequence_free(&seq);
|
||||
cfg->nof_layers = 1;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
if (grant->nof_tb != 1) {
|
||||
ERROR("Number of transport blocks is not supported for transmit diversity mode.");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
cfg->nof_layers = 2;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
if (grant->nof_tb == 1) {
|
||||
cfg->codebook_idx = pmi;
|
||||
cfg->nof_layers = 1;
|
||||
} else {
|
||||
cfg->codebook_idx = pmi + 1;
|
||||
cfg->nof_layers = 2;
|
||||
}
|
||||
INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n",
|
||||
grant->nof_tb, cfg->nof_layers, cfg->codebook_idx);
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
if (grant->nof_tb != 2) {
|
||||
ERROR("Number of transport blocks (%d) is not supported for CDD transmission mode.", grant->nof_tb);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
cfg->nof_layers = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
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.nof_bits*sizeof(int16_t));
|
||||
}
|
||||
|
||||
return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
} else {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_pdsch_encode(srslte_pdsch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
|
||||
uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS])
|
||||
static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data,
|
||||
uint32_t codeword_idx) {
|
||||
srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx];
|
||||
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx];
|
||||
uint32_t rv = cfg->rv[codeword_idx];
|
||||
|
||||
if (nbits->nof_bits) {
|
||||
INFO("Encoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
|
||||
cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
|
||||
nbits->nof_re, nbits->nof_bits, rv);
|
||||
|
||||
/* Channel coding */
|
||||
if (srslte_dlsch_encode2(&pdsch->dl_sch, cfg, softbuffer, data, pdsch->e[codeword_idx], codeword_idx)) {
|
||||
ERROR("Error encoding TB %d", codeword_idx);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
/* Bit scrambling */
|
||||
if (!pdsch->users[rnti]) {
|
||||
srslte_sequence_t seq;
|
||||
|
||||
if (srslte_sequence_pdsch(&seq, rnti, codeword_idx, 2 * cfg->sf_idx, pdsch->cell.id, nbits->nof_bits)) {
|
||||
ERROR("Initialising scrambling sequence");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_scrambling_bytes(&seq, (uint8_t *) pdsch->e[codeword_idx], nbits->nof_bits);
|
||||
srslte_sequence_free(&seq);
|
||||
|
||||
} else {
|
||||
srslte_scrambling_bytes(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx],
|
||||
(uint8_t *) pdsch->e[codeword_idx],
|
||||
nbits->nof_bits);
|
||||
}
|
||||
|
||||
/* Bit mapping */
|
||||
srslte_mod_modulate_bytes(&pdsch->mod[mcs->mod],
|
||||
(uint8_t *) pdsch->e[codeword_idx],
|
||||
pdsch->d[codeword_idx], nbits->nof_bits);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg,
|
||||
srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data,
|
||||
uint32_t codeword_idx) {
|
||||
srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx];
|
||||
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx];
|
||||
uint32_t rv = cfg->rv[codeword_idx];
|
||||
|
||||
if (nbits->nof_bits) {
|
||||
INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
|
||||
cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
|
||||
nbits->nof_re, nbits->nof_bits, rv);
|
||||
|
||||
/* demodulate symbols
|
||||
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
|
||||
* thus we don't need tot set it in the LLRs normalization
|
||||
*/
|
||||
srslte_demod_soft_demodulate_s(mcs->mod, pdsch->d[codeword_idx], pdsch->e[codeword_idx], nbits->nof_re);
|
||||
|
||||
if (pdsch->users[rnti] && pdsch->users[rnti]->sequence_generated) {
|
||||
srslte_scrambling_s_offset(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx], pdsch->e[codeword_idx],
|
||||
0, nbits->nof_bits);
|
||||
} else {
|
||||
srslte_sequence_t seq;
|
||||
if (srslte_sequence_pdsch(&seq, rnti, codeword_idx, 2 * cfg->sf_idx, pdsch->cell.id, nbits->nof_bits)) {
|
||||
ERROR("Initialising scrambling sequence");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_scrambling_s_offset(&seq, pdsch->e[codeword_idx], codeword_idx, nbits->nof_bits);
|
||||
srslte_sequence_free(&seq);
|
||||
}
|
||||
|
||||
return srslte_dlsch_decode2(&pdsch->dl_sch, cfg, softbuffer, pdsch->e[codeword_idx], data, codeword_idx);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/** Decodes the PDSCH from the received symbols
|
||||
*/
|
||||
int srslte_pdsch_decode(srslte_pdsch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
|
||||
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
float noise_estimate, uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
||||
bool acks[SRSLTE_MAX_CODEWORDS])
|
||||
{
|
||||
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
uint32_t i;
|
||||
cf_t *x[SRSLTE_MAX_LAYERS];
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
data != NULL &&
|
||||
cfg != NULL)
|
||||
{
|
||||
|
||||
INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d, mimo_type=%d, nof_layers=%d, nof_tb=%d\n",
|
||||
cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb, cfg->nof_layers, cfg->grant.nof_tb);
|
||||
|
||||
// Extract Symbols and Channel Estimates
|
||||
for (int j=0;j<q->nof_rx_antennas;j++) {
|
||||
int n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx);
|
||||
if (n != cfg->nbits[0].nof_re) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx);
|
||||
if (n != cfg->nbits[0].nof_re) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare layers
|
||||
int nof_symbols [SRSLTE_MAX_CODEWORDS];
|
||||
nof_symbols[0] = cfg->nbits[0].nof_re * cfg->grant.nof_tb / cfg->nof_layers;
|
||||
nof_symbols[1] = cfg->nbits[1].nof_re * cfg->grant.nof_tb / cfg->nof_layers;
|
||||
|
||||
if (cfg->nof_layers == cfg->grant.nof_tb) {
|
||||
/* Skip layer demap */
|
||||
for (i = 0; i < cfg->nof_layers; i++) {
|
||||
x[i] = q->d[i];
|
||||
}
|
||||
} else {
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < cfg->nof_layers; i++) {
|
||||
x[i] = q->x[i];
|
||||
}
|
||||
memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers));
|
||||
}
|
||||
|
||||
// Pre-decoder
|
||||
srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
|
||||
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate);
|
||||
|
||||
// Layer demapping only if necessary
|
||||
if (cfg->nof_layers != cfg->grant.nof_tb) {
|
||||
srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb,
|
||||
nof_symbols[0], nof_symbols, cfg->mimo_type);
|
||||
}
|
||||
|
||||
// Codeword decoding
|
||||
for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) {
|
||||
int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb);
|
||||
acks[tb] = (ret == SRSLTE_SUCCESS);
|
||||
}
|
||||
|
||||
pdsch_decode_debug(q, cfg, sf_symbols, ce);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
|
||||
} else {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_pdsch_pmi_select(srslte_pdsch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg,
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce,
|
||||
uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]) {
|
||||
|
||||
if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) {
|
||||
for (int nof_layers = 1; nof_layers <= 2; nof_layers++ ) {
|
||||
if (sinr[nof_layers - 1] && pmi) {
|
||||
if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1],
|
||||
sinr[nof_layers - 1]) < 0) {
|
||||
ERROR("PMI Select for %d layers", nof_layers);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ERROR("Not implemented configuration");
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdsch_cn_compute(srslte_pdsch_t *q,
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_ce, float *cn) {
|
||||
return srslte_precoding_cn(ce, q->cell.nof_ports, q->nof_rx_antennas, nof_ce, cn);
|
||||
}
|
||||
|
||||
int srslte_pdsch_encode(srslte_pdsch_t *q,
|
||||
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, 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)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
for (i=0;i<q->cell.nof_ports;i++) {
|
||||
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.tbs == 0) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (cfg->nbits.nof_re > q->max_re) {
|
||||
fprintf(stderr,
|
||||
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
|
||||
cfg->nbits.nof_re, q->max_re, q->cell.nof_prb);
|
||||
|
||||
/* If both transport block size is zero return error */
|
||||
if (cfg->grant.mcs[0].tbs == 0) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
INFO("Encoding PDSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
|
||||
cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs,
|
||||
cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv);
|
||||
|
||||
/* 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));
|
||||
|
||||
if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e)) {
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
return SRSLTE_ERROR;
|
||||
if (cfg->nbits[0].nof_re > q->max_re) {
|
||||
fprintf(stderr,
|
||||
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
|
||||
cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb);
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
/* scramble */
|
||||
if (q->users[rnti] && q->users[rnti]->sequence_generated) {
|
||||
srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits.nof_bits);
|
||||
} else {
|
||||
srslte_sequence_t seq;
|
||||
if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_scrambling_bytes(&seq, (uint8_t*) q->e, cfg->nbits.nof_bits);
|
||||
srslte_sequence_free(&seq);
|
||||
for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) {
|
||||
ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb);
|
||||
}
|
||||
|
||||
srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e, q->d, cfg->nbits.nof_bits);
|
||||
|
||||
/* TODO: only diversity supported */
|
||||
|
||||
// Layer mapping & precode if necessary
|
||||
if (q->cell.nof_ports > 1) {
|
||||
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, cfg->nbits.nof_re);
|
||||
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports,
|
||||
cfg->nbits.nof_re / q->cell.nof_ports);
|
||||
int nof_symbols;
|
||||
/* If number of layers is equal to transport blocks (codewords) skip layer mapping */
|
||||
if (cfg->nof_layers == cfg->grant.nof_tb) {
|
||||
for (i = 0; i < cfg->nof_layers; i++) {
|
||||
x[i] = q->d[i];
|
||||
}
|
||||
nof_symbols = cfg->nbits[0].nof_re;
|
||||
} else {
|
||||
/* Initialise layer map pointers */
|
||||
for (i = 0; i < cfg->nof_layers; i++) {
|
||||
x[i] = q->x[i];
|
||||
}
|
||||
memset(&x[cfg->nof_layers], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - cfg->nof_layers));
|
||||
|
||||
nof_symbols = srslte_layermap_type(q->d, x, cfg->grant.nof_tb, cfg->nof_layers,
|
||||
(int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits[0].nof_re, cfg->nbits[1].nof_re},
|
||||
cfg->mimo_type);
|
||||
}
|
||||
|
||||
/* Precode */
|
||||
srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx,
|
||||
nof_symbols, cfg->mimo_type);
|
||||
} else {
|
||||
memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t));
|
||||
memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t));
|
||||
}
|
||||
|
||||
/* mapping to resource elements */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
|
||||
srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx);
|
||||
}
|
||||
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
float srslte_pdsch_average_noi(srslte_pdsch_t *q)
|
||||
{
|
||||
void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter) {
|
||||
srslte_sch_set_max_noi(&q->dl_sch, max_iter);
|
||||
}
|
||||
|
||||
float srslte_pdsch_average_noi(srslte_pdsch_t *q) {
|
||||
return q->dl_sch.average_nof_iterations;
|
||||
}
|
||||
|
||||
|
|
|
@ -837,4 +837,4 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -492,44 +492,44 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
|
|||
fprintf(stderr, "Error decoding DCI: P/SI/RA-RNTI supports Format1A/1C only\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
grant->mcs.mod = SRSLTE_MOD_QPSK;
|
||||
grant->mcs.tbs = (uint32_t) tbs;
|
||||
grant->mcs[0].mod = SRSLTE_MOD_QPSK;
|
||||
grant->mcs[0].tbs = (uint32_t) tbs;
|
||||
} else {
|
||||
n_prb = grant->nof_prb;
|
||||
grant->nof_tb = 0;
|
||||
if (dci->tb_en[0]) {
|
||||
grant->mcs.idx = dci->mcs_idx;
|
||||
tbs = dl_fill_ra_mcs(&grant->mcs, n_prb);
|
||||
grant->mcs[0].idx = dci->mcs_idx;
|
||||
tbs = 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.tbs = last_dl_tbs[dci->harq_process%8];
|
||||
grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8];
|
||||
}
|
||||
grant->nof_tb++;
|
||||
} else {
|
||||
grant->mcs.tbs = 0;
|
||||
grant->mcs[0].tbs = 0;
|
||||
}
|
||||
if (dci->tb_en[1]) {
|
||||
grant->mcs2.idx = dci->mcs_idx_1;
|
||||
tbs = dl_fill_ra_mcs(&grant->mcs2, n_prb);
|
||||
grant->mcs[1].idx = dci->mcs_idx_1;
|
||||
tbs = dl_fill_ra_mcs(&grant->mcs[1], n_prb);
|
||||
if (tbs) {
|
||||
last_dl_tbs2[dci->harq_process%8] = tbs;
|
||||
} else {
|
||||
// For mcs>=29, set last TBS received for this PID
|
||||
grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8];
|
||||
grant->mcs[1].tbs = last_dl_tbs2[dci->harq_process%8];
|
||||
}
|
||||
grant->nof_tb++;
|
||||
} else {
|
||||
grant->mcs2.tbs = 0;
|
||||
grant->mcs[1].tbs = 0;
|
||||
}
|
||||
}
|
||||
if (dci->tb_en[0]) {
|
||||
grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod);
|
||||
}
|
||||
if (dci->tb_en[1]) {
|
||||
grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod);
|
||||
grant->nof_tb = 0;
|
||||
for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
|
||||
if (dci->tb_en[tb]) {
|
||||
grant->Qm[tb] = srslte_mod_bits_x_symbol(grant->mcs[tb].mod);
|
||||
grant->nof_tb++;
|
||||
}
|
||||
}
|
||||
grant->pinfo = dci->pinfo;
|
||||
|
||||
if (tbs < 0) {
|
||||
return SRSLTE_ERROR;
|
||||
} else {
|
||||
|
@ -537,13 +537,17 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
|
|||
}
|
||||
}
|
||||
|
||||
void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx, srslte_ra_nbits_t *nbits)
|
||||
void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx,
|
||||
srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS])
|
||||
{
|
||||
// Compute number of RE
|
||||
nbits->nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb<10?(cfi+1):cfi);
|
||||
nbits->lstart = cell.nof_prb<10?(cfi+1):cfi;
|
||||
nbits->nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nbits->lstart;
|
||||
nbits->nof_bits = nbits->nof_re * grant->Qm;
|
||||
for (int i = 0; i < grant->nof_tb; i++) {
|
||||
/* 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;
|
||||
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
|
||||
nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i];
|
||||
}
|
||||
}
|
||||
|
||||
/** Obtains a DL grant from a DCI grant for PDSCH */
|
||||
|
@ -796,18 +800,32 @@ void srslte_ra_pdsch_fprint(FILE *f, srslte_ra_dl_dci_t *dci, uint32_t nof_prb)
|
|||
}
|
||||
break;
|
||||
}
|
||||
fprintf(f, " - Modulation and coding scheme index:\t%d\n", dci->mcs_idx);
|
||||
fprintf(f, " - HARQ process:\t\t\t%d\n", dci->harq_process);
|
||||
fprintf(f, " - New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No");
|
||||
fprintf(f, " - Redundancy version:\t\t\t%d\n", dci->rv_idx);
|
||||
fprintf(f, " - TPC command for PUCCH:\t\t--\n");
|
||||
fprintf(f, " - Transport blocks swapped:\t\t%s\n", (dci->tb_cw_swap)?"true":"false");
|
||||
fprintf(f, " - Transport block 1 enabled:\t\t%s\n", (dci->tb_en[0])?"true":"false");
|
||||
if (dci->tb_en[0]) {
|
||||
fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx);
|
||||
fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No");
|
||||
fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx);
|
||||
}
|
||||
fprintf(f, " - Transport block 2 enabled:\t\t%s\n", (dci->tb_en[1])?"true":"false");
|
||||
if (dci->tb_en[1]) {
|
||||
fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx_1);
|
||||
fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi_1 ? "Yes" : "No");
|
||||
fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx_1);
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {
|
||||
srslte_ra_prb_fprint(f, grant);
|
||||
fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb);
|
||||
fprintf(f, " - Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs.mod));
|
||||
fprintf(f, " - Transport block size:\t\t%d\n", grant->mcs.tbs);
|
||||
fprintf(f, " - Number of TBs:\t\t\t%d\n", grant->nof_tb);
|
||||
for (int i = 0; i < grant->nof_tb; i++) {
|
||||
fprintf(f, " - Transport block:\t\t\t%d\n", i);
|
||||
fprintf(f, " -> Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs[i].mod));
|
||||
fprintf(f, " -> Transport block size:\t\t%d\n", grant->mcs[i].tbs);
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {
|
||||
|
|
|
@ -514,12 +514,22 @@ static int decode_tb(srslte_sch_t *q,
|
|||
}
|
||||
}
|
||||
|
||||
int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
|
||||
int16_t *e_bits, uint8_t *data)
|
||||
{
|
||||
return decode_tb(q,
|
||||
softbuffer, &cfg->cb_segm,
|
||||
cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits,
|
||||
int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
|
||||
int16_t *e_bits, uint8_t *data) {
|
||||
return srslte_dlsch_decode2(q, cfg, softbuffer, e_bits, data, 0);
|
||||
}
|
||||
|
||||
|
||||
int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
|
||||
int16_t *e_bits, uint8_t *data, int codeword_idx) {
|
||||
uint32_t Nl = 1;
|
||||
|
||||
if (cfg->nof_layers != cfg->grant.nof_tb) {
|
||||
Nl = 2;
|
||||
}
|
||||
|
||||
return decode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx],
|
||||
cfg->grant.Qm[codeword_idx] * Nl, cfg->rv[codeword_idx], cfg->nbits[codeword_idx].nof_bits,
|
||||
e_bits, data);
|
||||
}
|
||||
|
||||
|
@ -536,13 +546,22 @@ int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf
|
|||
int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
|
||||
uint8_t *data, uint8_t *e_bits)
|
||||
{
|
||||
return encode_tb(q,
|
||||
softbuffer, &cfg->cb_segm,
|
||||
cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits,
|
||||
data, e_bits);
|
||||
return srslte_dlsch_encode2(q, cfg, softbuffer, data, e_bits, 0);
|
||||
}
|
||||
|
||||
/* Compute the interleaving function on-the-fly, because it depends on number of RI bits
|
||||
int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
|
||||
uint8_t *data, uint8_t *e_bits, int codeword_idx) {
|
||||
uint32_t Nl = 1;
|
||||
|
||||
if (cfg->nof_layers != cfg->grant.nof_tb) {
|
||||
Nl = 2;
|
||||
}
|
||||
|
||||
return encode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx], cfg->grant.Qm[codeword_idx]*Nl, cfg->rv[codeword_idx],
|
||||
cfg->nbits[codeword_idx].nof_bits, data, e_bits);
|
||||
}
|
||||
|
||||
/* Compute the interleaving function on-the-fly, because it depends on number of RI bits
|
||||
* Profiling show that the computation of this matrix is neglegible.
|
||||
*/
|
||||
static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm,
|
||||
|
|
|
@ -85,7 +85,79 @@ target_link_libraries(pdsch_test srslte_phy)
|
|||
add_test(pdsch_test_qpsk pdsch_test -m 10 -n 50 -r 1)
|
||||
add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100)
|
||||
add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100 -r 2)
|
||||
add_test(pdsch_test_qam64 pdsch_test -m 28 -n 100)
|
||||
add_test(pdsch_test_qam64 pdsch_test -n 100)
|
||||
|
||||
# PDSCH test for single transmision mode and 2 Rx antennas
|
||||
add_test(pdsch_test_sin_6 pdsch_test -x single -a 2 -n 6)
|
||||
add_test(pdsch_test_sin_12 pdsch_test -x single -a 2 -n 12)
|
||||
add_test(pdsch_test_sin_25 pdsch_test -x single -a 2 -n 25)
|
||||
add_test(pdsch_test_sin_50 pdsch_test -x single -a 2 -n 50)
|
||||
add_test(pdsch_test_sin_75 pdsch_test -x single -a 2 -n 75)
|
||||
add_test(pdsch_test_sin_100 pdsch_test -x single -a 2 -n 100)
|
||||
|
||||
# PDSCH test for transmit diversity transmision mode (1 codeword)
|
||||
add_test(pdsch_test_div_6 pdsch_test -x diversity -a 2 -n 6)
|
||||
add_test(pdsch_test_div_12 pdsch_test -x diversity -a 2 -n 12)
|
||||
add_test(pdsch_test_div_25 pdsch_test -x diversity -a 2 -n 25)
|
||||
add_test(pdsch_test_div_50 pdsch_test -x diversity -a 2 -n 50)
|
||||
add_test(pdsch_test_div_75 pdsch_test -x diversity -a 2 -n 75)
|
||||
add_test(pdsch_test_div_100 pdsch_test -x diversity -a 2 -n 100)
|
||||
|
||||
# PDSCH test for CDD transmision mode (2 codeword)
|
||||
add_test(pdsch_test_cdd_6 pdsch_test -x cdd -a 2 -t 0 -n 6)
|
||||
add_test(pdsch_test_cdd_12 pdsch_test -x cdd -a 2 -t 0 -n 12)
|
||||
add_test(pdsch_test_cdd_25 pdsch_test -x cdd -a 2 -t 0 -n 25)
|
||||
add_test(pdsch_test_cdd_50 pdsch_test -x cdd -a 2 -t 0 -n 50)
|
||||
add_test(pdsch_test_cdd_75 pdsch_test -x cdd -a 2 -t 0 -n 75)
|
||||
add_test(pdsch_test_cdd_100 pdsch_test -x cdd -a 2 -t 0 -n 100)
|
||||
|
||||
# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (1 codeword)
|
||||
add_test(pdsch_test_multiplex1cw_p0_6 pdsch_test -x multiplex -a 2 -p 0 -n 6)
|
||||
add_test(pdsch_test_multiplex1cw_p0_12 pdsch_test -x multiplex -a 2 -p 0 -n 12)
|
||||
add_test(pdsch_test_multiplex1cw_p0_25 pdsch_test -x multiplex -a 2 -p 0 -n 25)
|
||||
add_test(pdsch_test_multiplex1cw_p0_50 pdsch_test -x multiplex -a 2 -p 0 -n 50)
|
||||
add_test(pdsch_test_multiplex1cw_p0_75 pdsch_test -x multiplex -a 2 -p 0 -n 75)
|
||||
add_test(pdsch_test_multiplex1cw_p0_100 pdsch_test -x multiplex -a 2 -p 0 -n 100)
|
||||
|
||||
# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (1 codeword)
|
||||
add_test(pdsch_test_multiplex1cw_p1_6 pdsch_test -x multiplex -a 2 -p 1 -n 6)
|
||||
add_test(pdsch_test_multiplex1cw_p1_12 pdsch_test -x multiplex -a 2 -p 1 -n 12)
|
||||
add_test(pdsch_test_multiplex1cw_p1_25 pdsch_test -x multiplex -a 2 -p 1 -n 25)
|
||||
add_test(pdsch_test_multiplex1cw_p1_50 pdsch_test -x multiplex -a 2 -p 1 -n 50)
|
||||
add_test(pdsch_test_multiplex1cw_p1_75 pdsch_test -x multiplex -a 2 -p 1 -n 75)
|
||||
add_test(pdsch_test_multiplex1cw_p1_100 pdsch_test -x multiplex -a 2 -p 1 -n 100)
|
||||
|
||||
# PDSCH test for Spatial Multiplex transmision mode with PMI = 2 (1 codeword)
|
||||
add_test(pdsch_test_multiplex1cw_p2_6 pdsch_test -x multiplex -a 2 -p 2 -n 6)
|
||||
add_test(pdsch_test_multiplex1cw_p2_12 pdsch_test -x multiplex -a 2 -p 2 -n 12)
|
||||
add_test(pdsch_test_multiplex1cw_p2_25 pdsch_test -x multiplex -a 2 -p 2 -n 25)
|
||||
add_test(pdsch_test_multiplex1cw_p2_50 pdsch_test -x multiplex -a 2 -p 2 -n 50)
|
||||
add_test(pdsch_test_multiplex1cw_p2_75 pdsch_test -x multiplex -a 2 -p 2 -n 75)
|
||||
add_test(pdsch_test_multiplex1cw_p2_100 pdsch_test -x multiplex -a 2 -p 2 -n 100)
|
||||
|
||||
# PDSCH test for Spatial Multiplex transmision mode with PMI = 3 (1 codeword)
|
||||
add_test(pdsch_test_multiplex1cw_p3_6 pdsch_test -x multiplex -a 2 -p 3 -n 6)
|
||||
add_test(pdsch_test_multiplex1cw_p3_12 pdsch_test -x multiplex -a 2 -p 3 -n 12)
|
||||
add_test(pdsch_test_multiplex1cw_p3_25 pdsch_test -x multiplex -a 2 -p 3 -n 25)
|
||||
add_test(pdsch_test_multiplex1cw_p3_50 pdsch_test -x multiplex -a 2 -p 3 -n 50)
|
||||
add_test(pdsch_test_multiplex1cw_p3_75 pdsch_test -x multiplex -a 2 -p 3 -n 75)
|
||||
add_test(pdsch_test_multiplex1cw_p3_100 pdsch_test -x multiplex -a 2 -p 3 -n 100)
|
||||
|
||||
# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (2 codeword)
|
||||
add_test(pdsch_test_multiplex2cw_p0_6 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 6)
|
||||
add_test(pdsch_test_multiplex2cw_p0_12 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 12)
|
||||
add_test(pdsch_test_multiplex2cw_p0_25 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 25)
|
||||
add_test(pdsch_test_multiplex2cw_p0_50 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 50)
|
||||
add_test(pdsch_test_multiplex2cw_p0_75 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 75)
|
||||
add_test(pdsch_test_multiplex2cw_p0_100 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 100)
|
||||
|
||||
# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (2 codeword)
|
||||
add_test(pdsch_test_multiplex2cw_p1_6 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 6)
|
||||
add_test(pdsch_test_multiplex2cw_p1_12 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 12)
|
||||
add_test(pdsch_test_multiplex2cw_p1_25 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 25)
|
||||
add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 50)
|
||||
add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75)
|
||||
add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100)
|
||||
|
||||
########################################################################
|
||||
# FILE TEST
|
||||
|
|
|
@ -43,9 +43,14 @@ void help()
|
|||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
int i;
|
||||
srslte_sch_t dlsch;
|
||||
srslte_pdsch_cfg_t cfg;
|
||||
srslte_softbuffer_tx_t softbuffer;
|
||||
srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS];
|
||||
uint32_t nof_codewords = 1;
|
||||
|
||||
memset(&dlsch, 0, sizeof(srslte_sch_t));
|
||||
memset(&cfg, 0, sizeof(srslte_pdsch_cfg_t));
|
||||
|
||||
if (nrhs < NOF_INPUTS) {
|
||||
help();
|
||||
|
@ -62,6 +67,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
srslte_verbose = SRSLTE_VERBOSE_NONE;
|
||||
|
||||
uint8_t *trblkin_bits = NULL;
|
||||
cfg.grant.nof_tb = 1;
|
||||
cfg.grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits);
|
||||
if (cfg.grant.mcs.tbs == 0) {
|
||||
mexErrMsgTxt("Error trblklen is zero\n");
|
||||
|
@ -76,6 +82,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
return;
|
||||
}
|
||||
|
||||
if (mexutils_read_uint32_struct(PUSCHCFG, "NLayers", &cfg.nof_layers)) {
|
||||
mexErrMsgTxt("Field NLayers not found in dlsch config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation");
|
||||
|
||||
if (!strcmp(mod_str, "QPSK")) {
|
||||
|
@ -94,9 +105,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
|
||||
mxFree(mod_str);
|
||||
|
||||
if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) {
|
||||
mexErrMsgTxt("Error initiating DL-SCH soft buffer\n");
|
||||
return;
|
||||
/* Initialise buffers */
|
||||
for (i = 0; i < nof_codewords; i++) {
|
||||
if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) {
|
||||
mexErrMsgTxt("Error initiating DL-SCH soft buffer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cfg.nbits.nof_bits = mxGetScalar(OUTLEN);
|
||||
|
@ -111,13 +125,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
uint32_t tmp_rv=cfg.rv;
|
||||
if (tmp_rv) {
|
||||
cfg.rv = 0;
|
||||
if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) {
|
||||
if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) {
|
||||
mexErrMsgTxt("Error encoding TB\n");
|
||||
return;
|
||||
}
|
||||
cfg.rv = tmp_rv;
|
||||
}
|
||||
if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) {
|
||||
if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) {
|
||||
mexErrMsgTxt("Error encoding TB\n");
|
||||
return;
|
||||
}
|
||||
|
@ -135,7 +149,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
free(trblkin);
|
||||
free(e_bits);
|
||||
free(e_bits_unpacked);
|
||||
|
||||
for (i = 0; i < nof_codewords; i++) {
|
||||
srslte_softbuffer_tx_free(&softbuffers[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,22 +27,26 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <srslte/phy/common/phy_common.h>
|
||||
#include <srslte/phy/phch/ra.h>
|
||||
#include <srslte/phy/phch/dci.h>
|
||||
#include <srslte/phy/phch/pdcch.h>
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
|
||||
srslte_cell_t cell = {
|
||||
6, // nof_prb
|
||||
1, // nof_ports
|
||||
1, // cell_id
|
||||
SRSLTE_CP_NORM, // cyclic prefix
|
||||
SRSLTE_PHICH_R_1, // PHICH resources
|
||||
SRSLTE_PHICH_NORM // PHICH length
|
||||
.nof_prb = 6,
|
||||
.nof_ports = 1,
|
||||
.id = 1,
|
||||
.cp = SRSLTE_CP_NORM,
|
||||
.phich_resources = SRSLTE_PHICH_R_1,
|
||||
.phich_length = SRSLTE_PHICH_NORM
|
||||
};
|
||||
|
||||
uint32_t cfi = 1;
|
||||
bool print_dci_table;
|
||||
uint32_t nof_rx_ant = 1;
|
||||
bool print_dci_table;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [cfpndv]\n", prog);
|
||||
|
@ -50,25 +54,29 @@ void usage(char *prog) {
|
|||
printf("\t-f cfi [Default %d]\n", cfi);
|
||||
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
|
||||
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
|
||||
printf("\t-A nof_rx_ant [Default %d]\n", nof_rx_ant);
|
||||
printf("\t-d Print DCI table [Default %s]\n", print_dci_table?"yes":"no");
|
||||
printf("\t-v [set srslte_verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "cfpndv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "cfpndvA")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
cell.nof_ports = atoi(argv[optind]);
|
||||
cell.nof_ports = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
cfi = atoi(argv[optind]);
|
||||
cfi = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
cell.nof_prb = atoi(argv[optind]);
|
||||
cell.nof_prb = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
cell.id = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'A':
|
||||
nof_rx_ant = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
print_dci_table = true;
|
||||
|
@ -85,25 +93,26 @@ void parse_args(int argc, char **argv) {
|
|||
|
||||
int test_dci_payload_size() {
|
||||
int i, j;
|
||||
int x[4];
|
||||
const srslte_dci_format_t formats[4] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C };
|
||||
int x[5];
|
||||
const srslte_dci_format_t formats[] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C, SRSLTE_DCI_FORMAT2A };
|
||||
const int prb[6] = { 6, 15, 25, 50, 75, 100 };
|
||||
const int dci_sz[6][5] = { { 21, 19, 21, 8 }, { 22, 23, 22, 10 }, { 25, 27,
|
||||
25, 12 }, { 27, 31, 27, 13 }, { 27, 33, 27, 14 }, { 28, 39, 28, 15 } };
|
||||
const int dci_sz[6][5] = { { 21, 19, 21, 8, 28 }, { 22, 23, 22, 10 , 31}, { 25, 27,
|
||||
25, 12 , 36}, { 27, 31, 27, 13 , 41}, { 27, 33, 27, 14 , 42}, { 28, 39, 28, 15, 48 }};
|
||||
|
||||
|
||||
printf("Testing DCI payload sizes...\n");
|
||||
printf(" PRB\t0\t1\t1A\t1C\n");
|
||||
printf(" PRB\t0\t1\t1A\t1C\t2A\n");
|
||||
for (i = 0; i < 6; i++) {
|
||||
int n = prb[i];
|
||||
for (j = 0; j < 4; j++) {
|
||||
x[j] = srslte_dci_format_sizeof(formats[j], n, 1);
|
||||
for (j = 0; j < 5; j++) {
|
||||
x[j] = srslte_dci_format_sizeof(formats[j], (uint32_t) n, 1);
|
||||
if (x[j] != dci_sz[i][j]) {
|
||||
fprintf(stderr, "Invalid DCI payload size for %s\n",
|
||||
srslte_dci_format_string(formats[j]));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
printf(" %2d:\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3]);
|
||||
printf(" %2d:\t%2d\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3], x[4]);
|
||||
}
|
||||
printf("Ok\n");
|
||||
|
||||
|
@ -111,8 +120,8 @@ int test_dci_payload_size() {
|
|||
printf("dci_sz_table[101][4] = {\n");
|
||||
for (i=0;i<=100;i++) {
|
||||
printf(" {");
|
||||
for (int j=0;j<4;j++) {
|
||||
printf("%d",srslte_dci_format_sizeof(formats[j], i, 1));
|
||||
for (j=0;j<4;j++) {
|
||||
printf("%d",srslte_dci_format_sizeof(formats[j], (uint32_t) i, 1));
|
||||
if (j<3) {
|
||||
printf(", ");
|
||||
}
|
||||
|
@ -128,16 +137,23 @@ int test_dci_payload_size() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
srslte_dci_msg_t dci_tx, dci_rx;
|
||||
srslte_dci_location_t dci_location;
|
||||
srslte_dci_format_t dci_format;
|
||||
srslte_ra_dl_dci_t ra_dl_tx;
|
||||
srslte_ra_dl_dci_t ra_dl_rx;
|
||||
} testcase_dci_t;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
srslte_pdcch_t pdcch;
|
||||
srslte_dci_msg_t dci_tx[2], dci_rx[2], dci_tmp;
|
||||
srslte_dci_location_t dci_locations[2];
|
||||
srslte_pdcch_t pdcch_tx, pdcch_rx;
|
||||
testcase_dci_t testcases[10] = {0};
|
||||
srslte_ra_dl_dci_t ra_dl;
|
||||
srslte_regs_t regs;
|
||||
int i, j;
|
||||
cf_t *ce[SRSLTE_MAX_PORTS];
|
||||
int i, j, k;
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
|
||||
int nof_re;
|
||||
cf_t *slot_symbols[SRSLTE_MAX_PORTS];
|
||||
cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS], *rx_slot_symbols[SRSLTE_MAX_PORTS];
|
||||
int nof_dcis;
|
||||
|
||||
int ret = -1;
|
||||
|
@ -152,19 +168,30 @@ int main(int argc, char **argv) {
|
|||
|
||||
/* init memory */
|
||||
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
ce[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!ce[i]) {
|
||||
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
|
||||
ce[i][j] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!ce[i][j]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
for (k = 0; k < nof_re; k++) {
|
||||
//ce[i][j][k] = (i == j) ? 1 : 0;
|
||||
ce[i][j][k] = ((float)rand()/(float)RAND_MAX) + _Complex_I*((float)rand()/(float)RAND_MAX);
|
||||
}
|
||||
}
|
||||
tx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!tx_slot_symbols[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
for (j = 0; j < nof_re; j++) {
|
||||
ce[i][j] = 1;
|
||||
}
|
||||
slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!slot_symbols[i]) {
|
||||
bzero(tx_slot_symbols[i], sizeof(cf_t) * nof_re);
|
||||
|
||||
rx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!rx_slot_symbols[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
bzero(rx_slot_symbols[i], sizeof(cf_t) * nof_re);
|
||||
}
|
||||
|
||||
if (srslte_regs_init(®s, cell)) {
|
||||
|
@ -177,12 +204,18 @@ int main(int argc, char **argv) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (srslte_pdcch_init(&pdcch, ®s, cell)) {
|
||||
if (srslte_pdcch_init_tx(&pdcch_tx, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
nof_dcis = 2;
|
||||
if (srslte_pdcch_init_rx(&pdcch_rx, ®s, cell, nof_rx_ant)) {
|
||||
fprintf(stderr, "Error creating PDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Resource allocate init */
|
||||
nof_dcis = 0;
|
||||
bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t));
|
||||
ra_dl.harq_process = 0;
|
||||
ra_dl.mcs_idx = 5;
|
||||
|
@ -190,62 +223,131 @@ int main(int argc, char **argv) {
|
|||
ra_dl.rv_idx = 0;
|
||||
ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
|
||||
ra_dl.type0_alloc.rbg_bitmask = 0x5;
|
||||
ra_dl.tb_en[0] = true;
|
||||
|
||||
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[0], cell.nof_prb, cell.nof_ports, false);
|
||||
srslte_dci_location_set(&dci_locations[0], 0, 0);
|
||||
/* Format 1 Test case */
|
||||
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1;
|
||||
testcases[nof_dcis].ra_dl_tx = ra_dl;
|
||||
nof_dcis++;
|
||||
|
||||
/* Format 1 Test case */
|
||||
ra_dl.mcs_idx = 15;
|
||||
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[1], cell.nof_prb, cell.nof_ports, false);
|
||||
srslte_dci_location_set(&dci_locations[1], 0, 1);
|
||||
|
||||
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1;
|
||||
testcases[nof_dcis].ra_dl_tx = ra_dl;
|
||||
nof_dcis++;
|
||||
|
||||
/* Tx Diversity Test case */
|
||||
if (cell.nof_ports > 1) {
|
||||
ra_dl.mcs_idx_1 = 0;
|
||||
ra_dl.rv_idx_1 = 0;
|
||||
ra_dl.ndi_1 = false;
|
||||
ra_dl.tb_en[1] = false;
|
||||
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A;
|
||||
testcases[nof_dcis].ra_dl_tx = ra_dl;
|
||||
nof_dcis++;
|
||||
}
|
||||
|
||||
/* CDD Spatial Multiplexing Test case */
|
||||
if (cell.nof_ports > 1) {
|
||||
ra_dl.mcs_idx_1 = 28;
|
||||
ra_dl.rv_idx_1 = 1;
|
||||
ra_dl.ndi_1 = false;
|
||||
ra_dl.tb_en[1] = true;
|
||||
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A;
|
||||
testcases[nof_dcis].ra_dl_tx = ra_dl;
|
||||
nof_dcis++;
|
||||
}
|
||||
|
||||
/* Execute Rx */
|
||||
for (i=0;i<nof_dcis;i++) {
|
||||
if (srslte_pdcch_encode(&pdcch, &dci_tx[i], dci_locations[i], 1234+i, slot_symbols, 0, cfi)) {
|
||||
srslte_dci_msg_pack_pdsch(&testcases[i].ra_dl_tx, testcases[i].dci_format, &testcases[i].dci_tx,
|
||||
cell.nof_prb, cell.nof_ports, false);
|
||||
srslte_dci_location_set(&testcases[i].dci_location, 0, (uint32_t) i);
|
||||
|
||||
if (srslte_pdcch_encode(&pdcch_tx, &testcases[i].dci_tx, testcases[i].dci_location, (uint16_t) (1234 + i),
|
||||
tx_slot_symbols, 0, cfi)) {
|
||||
fprintf(stderr, "Error encoding DCI message\n");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
srslte_vec_fprint_b(stdout, dci_tx[0].data, dci_tx[0].nof_bits);
|
||||
/* combine outputs */
|
||||
for (i = 1; i < cell.nof_ports; i++) {
|
||||
for (j = 0; j < nof_re; j++) {
|
||||
slot_symbols[0][j] += slot_symbols[i][j];
|
||||
/* Apply channel */
|
||||
for (j = 0; j < nof_rx_ant; j++) {
|
||||
for (k = 0; k < nof_re; k++) {
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
rx_slot_symbols[j][k] += tx_slot_symbols[i][k]*ce[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<2;i++) {
|
||||
if (srslte_pdcch_extract_llr(&pdcch, slot_symbols[0], ce, 0, 0, cfi)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
goto quit;
|
||||
}
|
||||
uint16_t crc_rem;
|
||||
if (srslte_pdcch_decode_msg(&pdcch, &dci_tmp, &dci_locations[i], SRSLTE_DCI_FORMAT1, &crc_rem)) {
|
||||
/* Execute 'Rx' */
|
||||
if (srslte_pdcch_extract_llr_multi(&pdcch_rx, rx_slot_symbols, ce, 0, 0, cfi)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
/* Decode DCIs */
|
||||
for (i=0;i<nof_dcis;i++) {
|
||||
uint16_t crc_rem;
|
||||
if (srslte_pdcch_decode_msg(&pdcch_rx, &testcases[i].dci_rx, &testcases[i].dci_location, testcases[i].dci_format, &crc_rem)) {
|
||||
fprintf(stderr, "Error decoding DCI message\n");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
if (srslte_dci_msg_unpack_pdsch(&testcases[i].dci_rx, &testcases[i].ra_dl_rx, cell.nof_prb, cell.nof_ports, false)) {
|
||||
fprintf(stderr, "Error unpacking DCI message\n");
|
||||
goto quit;
|
||||
}
|
||||
if (crc_rem >= 1234 && crc_rem < 1234 + nof_dcis) {
|
||||
crc_rem -= 1234;
|
||||
memcpy(&dci_rx[crc_rem], &dci_tmp, sizeof(srslte_dci_msg_t));
|
||||
} else {
|
||||
printf("Received invalid DCI CRC 0x%x\n", crc_rem);
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare Tx and Rx */
|
||||
for (i = 0; i < nof_dcis; i++) {
|
||||
if (memcmp(dci_tx[i].data, dci_rx[i].data, dci_tx[i].nof_bits)) {
|
||||
if (memcmp(testcases[i].dci_tx.data, testcases[i].dci_rx.data, testcases[i].dci_tx.nof_bits)) {
|
||||
printf("Error in DCI %d: Received data does not match\n", i);
|
||||
goto quit;
|
||||
}
|
||||
if (memcmp(&testcases[i].ra_dl_tx, &testcases[i].ra_dl_rx, sizeof(srslte_ra_dl_dci_t))) {
|
||||
printf("Error in RA %d: Received data does not match\n", i);
|
||||
printf(" Field | Tx | Rx \n");
|
||||
printf("--------------+----------+----------\n");
|
||||
printf(" harq_process | %8d | %8d\n", testcases[i].ra_dl_tx.harq_process, testcases[i].ra_dl_rx.harq_process);
|
||||
printf(" mcs_idx | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx, testcases[i].ra_dl_rx.mcs_idx);
|
||||
printf(" rv_idx | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx, testcases[i].ra_dl_rx.rv_idx);
|
||||
printf(" ndi | %8d | %8d\n", testcases[i].ra_dl_tx.ndi, testcases[i].ra_dl_rx.ndi);
|
||||
printf(" mcs_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx_1, testcases[i].ra_dl_rx.mcs_idx_1);
|
||||
printf(" rv_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx_1, testcases[i].ra_dl_rx.rv_idx_1);
|
||||
printf(" ndi_1 | %8d | %8d\n", testcases[i].ra_dl_tx.ndi_1, testcases[i].ra_dl_rx.ndi_1);
|
||||
printf(" tb_cw_swap | %8d | %8d\n", testcases[i].ra_dl_tx.tb_cw_swap, testcases[i].ra_dl_rx.tb_cw_swap);
|
||||
printf(" sram_id | %8d | %8d\n", testcases[i].ra_dl_tx.sram_id, testcases[i].ra_dl_rx.sram_id);
|
||||
printf(" pinfo | %8d | %8d\n", testcases[i].ra_dl_tx.pinfo, testcases[i].ra_dl_rx.pinfo);
|
||||
printf(" pconf | %8d | %8d\n", testcases[i].ra_dl_tx.pconf, testcases[i].ra_dl_rx.pconf);
|
||||
printf(" power_offset | %8d | %8d\n", testcases[i].ra_dl_tx.power_offset, testcases[i].ra_dl_rx.power_offset);
|
||||
printf(" tpc_pucch | %8d | %8d\n", testcases[i].ra_dl_tx.tpc_pucch, testcases[i].ra_dl_rx.tpc_pucch);
|
||||
printf(" tb_en[0] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[0], testcases[i].ra_dl_rx.tb_en[0]);
|
||||
printf(" tb_en[1] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[1], testcases[i].ra_dl_rx.tb_en[1]);
|
||||
printf(" dci_is_1a | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1a, testcases[i].ra_dl_rx.dci_is_1a);
|
||||
printf(" dci_is_1c | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1c, testcases[i].ra_dl_rx.dci_is_1c);
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
quit:
|
||||
srslte_pdcch_free(&pdcch);
|
||||
srslte_pdcch_free(&pdcch_tx);
|
||||
srslte_pdcch_free(&pdcch_rx);
|
||||
srslte_regs_free(®s);
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
free(ce[i]);
|
||||
free(slot_symbols[i]);
|
||||
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
|
||||
free(ce[i][j]);
|
||||
}
|
||||
free(tx_slot_symbols[i]);
|
||||
free(rx_slot_symbols[i]);
|
||||
}
|
||||
if (ret) {
|
||||
printf("Error\n");
|
||||
|
|
|
@ -33,13 +33,14 @@
|
|||
|
||||
#define ENBCFG prhs[0]
|
||||
#define RNTI prhs[1]
|
||||
#define INPUT prhs[2]
|
||||
#define NOF_INPUTS 3
|
||||
#define AMP prhs[2]
|
||||
#define INPUT prhs[3]
|
||||
#define NOF_INPUTS 4
|
||||
|
||||
|
||||
|
||||
srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1}; // SRSLTE_DCI_FORMAT1B should go here also
|
||||
const uint32_t nof_ue_formats = 2;
|
||||
srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1,SRSLTE_DCI_FORMAT2B}; // SRSLTE_DCI_FORMAT1B should go here also
|
||||
const uint32_t nof_ue_formats = 3;
|
||||
|
||||
srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
|
||||
const uint32_t nof_common_formats = 2;
|
||||
|
@ -162,7 +163,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
} else {
|
||||
noise_power = srslte_chest_dl_get_noise_estimate(&chest);
|
||||
}
|
||||
mexPrintf("noise power=%f, RNTI=0x%x, cfi=%d\n", noise_power, rnti, cfi);
|
||||
|
||||
float amplitude = mxGetScalar(AMP);
|
||||
|
||||
srslte_viterbi_set_gain_quant(&pdcch.decoder, amplitude);
|
||||
|
||||
srslte_pdcch_extract_llr(&pdcch, input_fft, ce, noise_power, sf_idx, cfi);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ uint32_t sf_idx = 0;
|
|||
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A;
|
||||
srslte_filesource_t fsrc;
|
||||
srslte_ue_dl_t ue_dl;
|
||||
cf_t *input_buffer;
|
||||
cf_t *input_buffer[SRSLTE_MAX_PORTS];
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [rovfcenmps] -i input_file\n", prog);
|
||||
|
@ -131,13 +131,13 @@ int base_init() {
|
|||
|
||||
flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb)));
|
||||
|
||||
input_buffer = malloc(flen * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
input_buffer[0] = malloc(flen * sizeof(cf_t));
|
||||
if (!input_buffer[0]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) {
|
||||
if (srslte_ue_dl_init(&ue_dl, cell, 1)) {
|
||||
fprintf(stderr, "Error initializing UE DL\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -151,12 +151,13 @@ int base_init() {
|
|||
void base_free() {
|
||||
srslte_filesource_free(&fsrc);
|
||||
srslte_ue_dl_free(&ue_dl);
|
||||
free(input_buffer);
|
||||
free(input_buffer[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int nof_frames;
|
||||
int ret;
|
||||
bool acks[SRSLTE_MAX_TB];
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
|
@ -169,15 +170,15 @@ int main(int argc, char **argv) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
uint8_t *data = malloc(100000);
|
||||
uint8_t *data[] = {malloc(100000)};
|
||||
|
||||
ret = -1;
|
||||
nof_frames = 0;
|
||||
do {
|
||||
srslte_filesource_read(&fsrc, input_buffer, flen);
|
||||
srslte_filesource_read(&fsrc, input_buffer[0], flen);
|
||||
INFO("Reading %d samples sub-frame %d\n", flen, sf_idx);
|
||||
|
||||
ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, sf_idx);
|
||||
ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, 0, sf_idx, acks);
|
||||
if(ret > 0) {
|
||||
printf("PDSCH Decoded OK!\n");
|
||||
} else if (ret == 0) {
|
||||
|
@ -190,7 +191,8 @@ int main(int argc, char **argv) {
|
|||
} while (nof_frames <= max_frames && ret == 0);
|
||||
|
||||
base_free();
|
||||
if (ret > 0) {
|
||||
free(data[0]);
|
||||
if (ret > 0) {
|
||||
exit(0);
|
||||
} else {
|
||||
exit(-1);
|
||||
|
|
|
@ -27,60 +27,80 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <srslte/phy/phch/ra.h>
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
|
||||
// Enable to measure execution time
|
||||
//#define DO_OFDM
|
||||
|
||||
#ifdef DO_OFDM
|
||||
#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb)
|
||||
#else
|
||||
#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)
|
||||
#endif
|
||||
|
||||
srslte_cell_t cell = {
|
||||
6, // nof_prb
|
||||
1, // nof_ports
|
||||
0, // cell_id
|
||||
SRSLTE_CP_NORM, // cyclic prefix
|
||||
SRSLTE_PHICH_R_1_6, // PHICH resources
|
||||
SRSLTE_PHICH_NORM // PHICH length
|
||||
SRSLTE_PHICH_NORM, // PHICH length
|
||||
SRSLTE_PHICH_R_1_6 // PHICH resources
|
||||
};
|
||||
|
||||
char mimo_type_str [32] = "single";
|
||||
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
uint32_t cfi = 2;
|
||||
uint32_t mcs = 0;
|
||||
uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0};
|
||||
uint32_t subframe = 1;
|
||||
uint32_t rv_idx = 0;
|
||||
uint16_t rnti = 1234;
|
||||
int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1};
|
||||
uint16_t rnti = 1234;
|
||||
uint32_t nof_rx_antennas = 1;
|
||||
uint32_t pmi = 0;
|
||||
char *input_file = NULL;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [fmcsrRFpnv] \n", prog);
|
||||
printf("Usage: %s [fmMcsrtRFpnwav] \n", prog);
|
||||
printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n");
|
||||
printf("\t-m MCS [Default %d]\n", mcs);
|
||||
printf("\t-m MCS [Default %d]\n", mcs[0]);
|
||||
printf("\t-M MCS2 [Default %d]\n", mcs[1]);
|
||||
printf("\t-c cell id [Default %d]\n", cell.id);
|
||||
printf("\t-s subframe [Default %d]\n", subframe);
|
||||
printf("\t-r rv_idx [Default %d]\n", rv_idx);
|
||||
printf("\t-r rv_idx [Default %d]\n", rv_idx[0]);
|
||||
printf("\t-t rv_idx2 [Default %d]\n", rv_idx[1]);
|
||||
printf("\t-R rnti [Default %d]\n", rnti);
|
||||
printf("\t-F cfi [Default %d]\n", cfi);
|
||||
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
|
||||
printf("\t-x Transmission mode [single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
|
||||
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
|
||||
printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas);
|
||||
printf("\t-p pmi (multiplex only) [Default %d]\n", pmi);
|
||||
printf("\t-v [set srslte_verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "fmcsrRFpnv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) {
|
||||
switch(opt) {
|
||||
case 'f':
|
||||
input_file = argv[optind];
|
||||
break;
|
||||
case 'm':
|
||||
mcs = atoi(argv[optind]);
|
||||
mcs[0] = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'M':
|
||||
mcs[1] = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
subframe = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
rv_idx = atoi(argv[optind]);
|
||||
rv_idx[0] = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
rv_idx[1] = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'R':
|
||||
rnti = atoi(argv[optind]);
|
||||
|
@ -88,8 +108,11 @@ void parse_args(int argc, char **argv) {
|
|||
case 'F':
|
||||
cfi = atoi(argv[optind]);
|
||||
break;
|
||||
case 'x':
|
||||
strncpy(mimo_type_str, argv[optind], 32);
|
||||
break;
|
||||
case 'p':
|
||||
cell.nof_ports = atoi(argv[optind]);
|
||||
pmi = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
cell.nof_prb = atoi(argv[optind]);
|
||||
|
@ -97,6 +120,9 @@ void parse_args(int argc, char **argv) {
|
|||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'a':
|
||||
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
|
@ -107,191 +133,389 @@ void parse_args(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t *data = NULL;
|
||||
cf_t *ce[SRSLTE_MAX_PORTS];
|
||||
srslte_softbuffer_rx_t softbuffer_rx;
|
||||
static uint8_t *data_tx[SRSLTE_MAX_CODEWORDS] = {NULL};
|
||||
static uint8_t *data_rx[SRSLTE_MAX_CODEWORDS] = {NULL};
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
|
||||
srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS];
|
||||
srslte_ra_dl_grant_t grant;
|
||||
srslte_pdsch_cfg_t pdsch_cfg;
|
||||
cf_t *sf_symbols;
|
||||
cf_t *slot_symbols[SRSLTE_MAX_PORTS];
|
||||
srslte_pdsch_t pdsch;
|
||||
#ifdef DO_OFDM
|
||||
cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS];
|
||||
cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS];
|
||||
#endif /* DO_OFDM */
|
||||
cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS];
|
||||
cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS];
|
||||
srslte_pdsch_t pdsch_tx, pdsch_rx;
|
||||
srslte_ofdm_t ofdm_tx, ofdm_rx;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
uint32_t i, j;
|
||||
uint32_t i, j, k;
|
||||
int ret = -1;
|
||||
struct timeval t[3];
|
||||
srslte_softbuffer_tx_t softbuffer_tx;
|
||||
|
||||
srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS];
|
||||
int M=10;
|
||||
bool acks[SRSLTE_MAX_CODEWORDS] = {false};
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
bzero(&pdsch, sizeof(srslte_pdsch_t));
|
||||
/* Initialise to zeros */
|
||||
bzero(&pdsch_tx, sizeof(srslte_pdsch_t));
|
||||
bzero(&pdsch_rx, sizeof(srslte_pdsch_t));
|
||||
bzero(&pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
|
||||
bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
|
||||
bzero(slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
|
||||
bzero(&softbuffer_rx, sizeof(srslte_softbuffer_rx_t));
|
||||
bzero(&softbuffer_tx, sizeof(srslte_softbuffer_tx_t));
|
||||
|
||||
bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
|
||||
bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
|
||||
|
||||
/* Parse transmission mode */
|
||||
if (srslte_str2mimotype(mimo_type_str, &mimo_type)) {
|
||||
ERROR("Wrong transmission mode.");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
switch(mimo_type) {
|
||||
|
||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||
cell.nof_ports = 1;
|
||||
break;
|
||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||
case SRSLTE_MIMO_TYPE_CDD:
|
||||
if (nof_rx_antennas < 2) {
|
||||
ERROR("At least two receiving antennas are required");
|
||||
goto quit;
|
||||
}
|
||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||
default:
|
||||
cell.nof_ports = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
srslte_ra_dl_dci_t dci;
|
||||
bzero(&dci, sizeof(srslte_ra_dl_dci_t));
|
||||
dci.mcs_idx = mcs;
|
||||
dci.rv_idx = rv_idx;
|
||||
dci.type0_alloc.rbg_bitmask = 0xffffffff;
|
||||
dci.tb_en[0] = true;
|
||||
|
||||
/* If transport block 0 is enabled */
|
||||
if (mcs[0] != 0 || rv_idx[0] != 1) {
|
||||
dci.mcs_idx = mcs[0];
|
||||
dci.rv_idx = rv_idx[0];
|
||||
dci.tb_en[0] = true;
|
||||
}
|
||||
|
||||
/* If transport block 0 is disabled */
|
||||
if (mcs[1] != 0 || rv_idx[1] != 1) {
|
||||
dci.mcs_idx_1 = mcs[1];
|
||||
dci.rv_idx_1 = rv_idx[1];
|
||||
dci.tb_en[1] = true;
|
||||
}
|
||||
|
||||
/* Generate grant from DCI */
|
||||
if (srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant)) {
|
||||
fprintf(stderr, "Error computing resource allocation\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef DO_OFDM
|
||||
srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb);
|
||||
srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb);
|
||||
|
||||
sf_symbols=srslte_vec_malloc(sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
|
||||
srslte_ofdm_set_normalize(&ofdm_tx, true);
|
||||
srslte_ofdm_set_normalize(&ofdm_rx, true);
|
||||
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
}
|
||||
|
||||
for (i = 0; i < nof_rx_antennas; i++) {
|
||||
rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
}
|
||||
#endif /* DO_OFDM */
|
||||
|
||||
/* Configure PDSCH */
|
||||
if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx)) {
|
||||
if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, mimo_type, pmi)) {
|
||||
fprintf(stderr, "Error configuring PDSCH\n");
|
||||
exit(-1);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
/* init memory */
|
||||
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
|
||||
ce[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
|
||||
if (!ce[i]) {
|
||||
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
|
||||
ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * NOF_CE_SYMBOLS);
|
||||
if (!ce[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
goto quit;
|
||||
}
|
||||
for (k = 0; k < NOF_CE_SYMBOLS; k++) {
|
||||
ce[i][j][k] = (i == j) ? 1.0f : 0.0f;
|
||||
}
|
||||
}
|
||||
rx_slot_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
|
||||
if (!rx_slot_symbols[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
goto quit;
|
||||
}
|
||||
for (j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
|
||||
ce[i][j] = 1;
|
||||
}
|
||||
slot_symbols[i] = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
|
||||
if (!slot_symbols[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
data = srslte_vec_malloc(sizeof(uint8_t) * (grant.mcs.tbs/8)+24);
|
||||
if (!data) {
|
||||
perror("srslte_vec_malloc");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (srslte_pdsch_init(&pdsch, cell)) {
|
||||
|
||||
for (int i = 0; i < grant.nof_tb; i++) {
|
||||
if (grant.mcs[i].tbs) {
|
||||
data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs);
|
||||
if (!data_tx[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
goto quit;
|
||||
}
|
||||
bzero(data_tx[i], sizeof(uint8_t) * grant.mcs[i].tbs);
|
||||
|
||||
data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs);
|
||||
if (!data_rx[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
goto quit;
|
||||
}
|
||||
bzero(data_rx[i], sizeof(uint8_t) * grant.mcs[i].tbs);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (srslte_pdsch_init_rx(&pdsch_rx, cell, nof_rx_antennas)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
srslte_pdsch_set_rnti(&pdsch, rnti);
|
||||
|
||||
if (srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating RX soft buffer\n");
|
||||
goto quit;
|
||||
|
||||
srslte_pdsch_set_rnti(&pdsch_rx, rnti);
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
softbuffers_rx[i] = calloc(sizeof(srslte_softbuffer_rx_t), 1);
|
||||
if (!softbuffers_rx[i]) {
|
||||
fprintf(stderr, "Error allocating RX soft buffer\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (srslte_softbuffer_rx_init(softbuffers_rx[i], cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating RX soft buffer\n");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
INFO(" Global:\n");
|
||||
INFO(" nof_prb=%d\n", cell.nof_prb);
|
||||
INFO(" nof_ports=%d\n", cell.nof_ports);
|
||||
INFO(" id=%d\n", cell.id);
|
||||
INFO(" cp=%s\n", srslte_cp_string(cell.cp));
|
||||
INFO(" phich_length=%d\n", (int) cell.phich_length);
|
||||
INFO(" phich_resources=%d\n", (int) cell.phich_resources);
|
||||
INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb);
|
||||
INFO(" nof_prb=%d\n", pdsch_cfg.grant.nof_prb);
|
||||
INFO(" sf_idx=%d\n", pdsch_cfg.sf_idx);
|
||||
INFO(" mimo_type=%s\n", srslte_mimotype2str(pdsch_cfg.mimo_type));
|
||||
INFO(" nof_layers=%d\n", pdsch_cfg.nof_layers);
|
||||
INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb);
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
INFO(" Tranport block index %d:\n", i);
|
||||
INFO(" Qm=%d\n", pdsch_cfg.grant.Qm[i]);
|
||||
INFO(" mcs.idx=0x%X\n", pdsch_cfg.grant.mcs[i].idx);
|
||||
INFO(" mcs.tbs=%d\n", pdsch_cfg.grant.mcs[i].tbs);
|
||||
INFO(" mcs.mod=%s\n", srslte_mod_string(pdsch_cfg.grant.mcs[i].mod));
|
||||
INFO(" rv=%d\n", pdsch_cfg.rv[i]);
|
||||
INFO(" lstart=%d\n", pdsch_cfg.nbits[i].lstart);
|
||||
INFO(" nof_bits=%d\n", pdsch_cfg.nbits[i].nof_bits);
|
||||
INFO(" nof_re=%d\n", pdsch_cfg.nbits[i].nof_re);
|
||||
INFO(" nof_symb=%d\n", pdsch_cfg.nbits[i].nof_symb);
|
||||
}
|
||||
|
||||
if (input_file) {
|
||||
srslte_filesource_t fsrc;
|
||||
if (srslte_filesource_init(&fsrc, input_file, SRSLTE_COMPLEX_FLOAT_BIN)) {
|
||||
fprintf(stderr, "Error opening file %s\n", input_file);
|
||||
exit(-1);
|
||||
goto quit;
|
||||
}
|
||||
#ifdef DO_OFDM
|
||||
srslte_filesource_read(&fsrc, sf_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
srslte_filesource_read(&fsrc, rx_slot_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
#else
|
||||
srslte_filesource_read(&fsrc, slot_symbols[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
|
||||
srslte_filesource_read(&fsrc, rx_slot_symbols[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
|
||||
#endif
|
||||
|
||||
srslte_chest_dl_t chest;
|
||||
if (srslte_chest_dl_init(&chest, cell)) {
|
||||
printf("Error initializing equalizer\n");
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
exit(-1);
|
||||
}
|
||||
srslte_chest_dl_estimate(&chest, slot_symbols[0], ce, subframe);
|
||||
srslte_chest_dl_estimate(&chest, rx_slot_symbols[0], ce[0], subframe);
|
||||
srslte_chest_dl_free(&chest);
|
||||
|
||||
srslte_filesource_free(&fsrc);
|
||||
} else {
|
||||
if (srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating TX soft buffer\n");
|
||||
} else {
|
||||
|
||||
if (srslte_pdsch_init_tx(&pdsch_tx, cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
for (i=0;i<grant.mcs.tbs/8;i++) {
|
||||
data[i] = rand()%256;
|
||||
}
|
||||
|
||||
uint8_t databit[100000];
|
||||
srslte_bit_unpack_vector(data, databit, grant.mcs.tbs);
|
||||
srslte_vec_save_file("data_in", databit, grant.mcs.tbs);
|
||||
|
||||
if (!input_file) {
|
||||
|
||||
if (rv_idx) {
|
||||
/* Do 1st transmission for rv_idx!=0 */
|
||||
pdsch_cfg.rv = 0;
|
||||
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer_tx, data, rnti, slot_symbols)) {
|
||||
fprintf(stderr, "Error encoding PDSCH\n");
|
||||
goto quit;
|
||||
}
|
||||
srslte_pdsch_set_rnti(&pdsch_tx, rnti);
|
||||
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
softbuffers_tx[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
|
||||
if (!softbuffers_tx[i]) {
|
||||
fprintf(stderr, "Error allocating TX soft buffer\n");
|
||||
}
|
||||
pdsch_cfg.rv = rv_idx;
|
||||
|
||||
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer_tx, data, rnti, slot_symbols)) {
|
||||
|
||||
if (srslte_softbuffer_tx_init(softbuffers_tx[i], cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating TX soft buffer\n");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
tx_slot_symbols[i] = calloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), sizeof(cf_t));
|
||||
if (!tx_slot_symbols[i]) {
|
||||
perror("srslte_vec_malloc");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
for (int tb = 0; tb < grant.nof_tb; tb++) {
|
||||
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
|
||||
data_tx[tb][byte] = (uint8_t)(rand() % 256);
|
||||
}
|
||||
}
|
||||
|
||||
/*uint8_t databit[100000];
|
||||
srslte_bit_unpack_vector(data, databit, grant.mcs.tbs);
|
||||
srslte_vec_save_file("data_in", databit, grant.mcs.tbs);*/
|
||||
|
||||
if (rv_idx[0] != 0 || rv_idx[1] != 0) {
|
||||
/* Do 1st transmission for rv_idx!=0 */
|
||||
bzero(pdsch_cfg.rv, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS);
|
||||
if (srslte_pdsch_encode(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) {
|
||||
fprintf(stderr, "Error encoding PDSCH\n");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
/* combine outputs */
|
||||
for (i=0;i<cell.nof_ports;i++) {
|
||||
for (j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
|
||||
if (i > 0) {
|
||||
slot_symbols[0][j] += slot_symbols[i][j];
|
||||
}
|
||||
ce[i][j] = 1;
|
||||
memcpy(pdsch_cfg.rv, rv_idx, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS);
|
||||
gettimeofday(&t[1], NULL);
|
||||
for (k = 0; k < M; k++) {
|
||||
if (srslte_pdsch_encode(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) {
|
||||
ERROR("Error encoding PDSCH");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
printf("ENCODED in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n",
|
||||
(float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f,
|
||||
(float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec);
|
||||
|
||||
#ifdef DO_OFDM
|
||||
srslte_ofdm_tx_sf(&ofdm_tx, slot_symbols[0], sf_symbols);
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
/* For each Tx antenna modulate OFDM */
|
||||
srslte_ofdm_tx_sf(&ofdm_tx, tx_slot_symbols[i], tx_sf_symbols[i]);
|
||||
}
|
||||
|
||||
/* combine outputs */
|
||||
for (j = 0; j < nof_rx_antennas; j++) {
|
||||
for (k = 0; k < NOF_CE_SYMBOLS; k++) {
|
||||
rx_sf_symbols[j][k] = 0.0f;
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
rx_sf_symbols[j][k] += tx_sf_symbols[i][k] * ce[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* combine outputs */
|
||||
for (j = 0; j < nof_rx_antennas; j++) {
|
||||
for (k = 0; k < SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); k++) {
|
||||
rx_slot_symbols[j][k] = 0.0f;
|
||||
for (i = 0; i < cell.nof_ports; i++) {
|
||||
rx_slot_symbols[j][k] += tx_slot_symbols[i][k] * ce[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
int M=1;
|
||||
int r=0;
|
||||
srslte_sch_set_max_noi(&pdsch.dl_sch, 10);
|
||||
|
||||
|
||||
}
|
||||
int r=0;
|
||||
srslte_pdsch_set_max_noi(&pdsch_rx, 10);
|
||||
|
||||
gettimeofday(&t[1], NULL);
|
||||
for (i=0;i<M;i++) {
|
||||
#ifdef DO_OFDM
|
||||
srslte_ofdm_rx_sf(&ofdm_rx, sf_symbols, slot_symbols[1]);
|
||||
#endif
|
||||
srslte_softbuffer_rx_reset_tbs(&softbuffer_rx, grant.mcs.tbs);
|
||||
r = srslte_pdsch_decode(&pdsch, &pdsch_cfg, &softbuffer_rx, slot_symbols[0], ce, 0, rnti, data);
|
||||
for (k = 0; k < M; k++) {
|
||||
#ifdef DO_OFDM
|
||||
/* For each Rx antenna demodulate OFDM */
|
||||
for (i = 0; i < nof_rx_antennas; i++) {
|
||||
srslte_ofdm_rx_sf(&ofdm_rx, tx_sf_symbols[i], rx_slot_symbols[i]);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < grant.nof_tb; i++) {
|
||||
if (grant.mcs[i].tbs) {
|
||||
srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs);
|
||||
}
|
||||
}
|
||||
r = srslte_pdsch_decode(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks);
|
||||
}
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
printf("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK",
|
||||
(float) t[0].tv_usec/M, (float) grant.mcs.tbs/1000, (float) grant.mcs.tbs*M/t[0].tv_usec);
|
||||
(float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f,
|
||||
(float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec);
|
||||
|
||||
/* If there is an error in PDSCH decode */
|
||||
if (r) {
|
||||
ret = -1;
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
quit:
|
||||
srslte_pdsch_free(&pdsch);
|
||||
srslte_softbuffer_tx_free(&softbuffer_tx);
|
||||
srslte_softbuffer_rx_free(&softbuffer_rx);
|
||||
|
||||
for (i=0;i<cell.nof_ports;i++) {
|
||||
if (ce[i]) {
|
||||
free(ce[i]);
|
||||
}
|
||||
if (slot_symbols[i]) {
|
||||
free(slot_symbols[i]);
|
||||
/* Check Tx and Rx bytes */
|
||||
for (int tb = 0; tb < grant.nof_tb; tb++) {
|
||||
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
|
||||
if (data_tx[tb][byte] != data_rx[tb][byte]) {
|
||||
ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]);
|
||||
ret = SRSLTE_ERROR;
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
free(data);
|
||||
|
||||
/* Check all transport blocks have been decoded OK */
|
||||
for (int tb = 0; tb < grant.nof_tb; tb++) {
|
||||
ret |= (acks[tb]) ? SRSLTE_SUCCESS : SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
|
||||
quit:
|
||||
srslte_pdsch_free(&pdsch_tx);
|
||||
srslte_pdsch_free(&pdsch_rx);
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
srslte_softbuffer_tx_free(softbuffers_tx[i]);
|
||||
if (softbuffers_tx[i]) {
|
||||
free(softbuffers_tx[i]);
|
||||
}
|
||||
|
||||
srslte_softbuffer_rx_free(softbuffers_rx[i]);
|
||||
if (softbuffers_rx[i]) {
|
||||
free(softbuffers_rx[i]);
|
||||
}
|
||||
|
||||
if (data_tx[i]) {
|
||||
free(data_tx[i]);
|
||||
}
|
||||
|
||||
if (data_rx[i]) {
|
||||
free(data_rx[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
|
||||
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
|
||||
if (ce[i][j]) {
|
||||
free(ce[i][j]);
|
||||
}
|
||||
}
|
||||
if (tx_slot_symbols[i]) {
|
||||
free(tx_slot_symbols[i]);
|
||||
}
|
||||
if (rx_slot_symbols[i]) {
|
||||
free(rx_slot_symbols[i]);
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
printf("Error\n");
|
||||
|
|
|
@ -101,7 +101,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
nof_antennas = dims[2];
|
||||
}
|
||||
|
||||
if (srslte_pdsch_init_multi(&pdsch, cell, nof_antennas)) {
|
||||
if (srslte_pdsch_init_rx_multi(&pdsch, cell, nof_antennas)) {
|
||||
mexErrMsgTxt("Error initiating PDSCH\n");
|
||||
return;
|
||||
}
|
||||
|
@ -202,11 +202,18 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
ce[i][j] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
|
||||
}
|
||||
}
|
||||
uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8);
|
||||
if (!data_bytes) {
|
||||
uint8_t *data_bytes[SRSLTE_MAX_CODEWORDS];
|
||||
data_bytes[0] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8);
|
||||
if (!data_bytes[0]) {
|
||||
return;
|
||||
}
|
||||
srslte_sch_set_max_noi(&pdsch.dl_sch, max_iterations);
|
||||
|
||||
data_bytes[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs2.tbs/8);
|
||||
if (!data_bytes[1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
srslte_pdsch_set_max_noi(&pdsch, max_iterations);
|
||||
|
||||
bool input_fft_allocated = false;
|
||||
int r=-1;
|
||||
|
@ -272,7 +279,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
}
|
||||
|
||||
uint8_t *data = malloc(grant.mcs.tbs);
|
||||
srslte_bit_unpack_vector(data_bytes, data, grant.mcs.tbs);
|
||||
srslte_bit_unpack_vector(data_bytes[0], data, grant.mcs.tbs);
|
||||
|
||||
if (nlhs >= 1) {
|
||||
plhs[0] = mxCreateLogicalScalar(r == 0);
|
||||
|
@ -284,10 +291,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
mexutils_write_cf(pdsch.symbols[0], &plhs[2], cfg.nbits.nof_re, 1);
|
||||
}
|
||||
if (nlhs >= 4) {
|
||||
mexutils_write_cf(pdsch.d, &plhs[3], cfg.nbits.nof_re, 1);
|
||||
mexutils_write_cf(pdsch.d[0], &plhs[3], cfg.nbits.nof_re, 1);
|
||||
}
|
||||
if (nlhs >= 5) {
|
||||
mexutils_write_s(pdsch.e, &plhs[4], cfg.nbits.nof_bits, 1);
|
||||
mexutils_write_s(pdsch.e[0], &plhs[4], cfg.nbits.nof_bits, 1);
|
||||
}
|
||||
if (nlhs >= 6) {
|
||||
uint32_t len = nof_antennas*cell.nof_ports*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);
|
||||
|
@ -323,7 +330,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
}
|
||||
}
|
||||
}
|
||||
free(data_bytes);
|
||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
if (data_bytes[i]) {
|
||||
free(data_bytes[i]);
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
|
||||
return;
|
||||
|
|
|
@ -104,6 +104,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
srslte_prach_set_detect_factor(&prach, factor);
|
||||
}
|
||||
|
||||
mexPrintf("format=%d config=%d, N_cp=%d, ifft=%d\n", prach.f, prach.config_idx, prach.N_cp, prach.N_ifft_ul);
|
||||
|
||||
if (srslte_prach_detect_offset(&prach, frequency_offset, &input_signal[prach.N_cp], nof_samples, preambles, offsets, NULL, &nof_detected)) {
|
||||
mexErrMsgTxt("Error detecting PRACH\n");
|
||||
return;
|
||||
|
|
|
@ -172,7 +172,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
|
||||
srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en);
|
||||
|
||||
if (srslte_pucch_encode(&pucch, format, n_pucch, sf_idx, bits, sf_symbols)) {
|
||||
if (srslte_pucch_encode(&pucch, format, n_pucch, sf_idx, (uint16_t) rnti, bits, sf_symbols)) {
|
||||
mexErrMsgTxt("Error encoding PUCCH\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -187,12 +187,14 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
|
||||
srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en);
|
||||
|
||||
if (srslte_chest_ul_estimate_pucch(&chest_ul, sf_symbols, ce, format, n_pucch, sf_idx)) {
|
||||
uint8_t pucch2_ack_bits[2] = {0};
|
||||
|
||||
if (srslte_chest_ul_estimate_pucch(&chest_ul, sf_symbols, ce, format, n_pucch, sf_idx, &pucch2_ack_bits)) {
|
||||
mexErrMsgTxt("Error estimating PUCCH DMRS\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, sf_symbols, ce, 0, bits)<0) {
|
||||
if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, (uint16_t) rnti, sf_symbols, ce, 0, bits)<0) {
|
||||
mexErrMsgTxt("Error decoding PUCCH\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ float rf_blade_get_rssi(void *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int rf_blade_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
|
||||
int rf_blade_open_multi(char *args, void **h, uint32_t nof_channels)
|
||||
{
|
||||
return rf_blade_open(args, h);
|
||||
}
|
||||
|
@ -469,6 +469,20 @@ int rf_blade_recv_with_time(void *h,
|
|||
return nsamples;
|
||||
}
|
||||
|
||||
int rf_blade_send_timed_multi(void *h,
|
||||
void *data[4],
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst)
|
||||
{
|
||||
return rf_blade_send_timed(h, data[0], nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst,
|
||||
is_end_of_burst);
|
||||
}
|
||||
|
||||
int rf_blade_send_timed(void *h,
|
||||
void *data,
|
||||
int nsamples,
|
||||
|
|
|
@ -34,7 +34,7 @@ SRSLTE_API int rf_blade_open(char *args,
|
|||
void **handler);
|
||||
|
||||
SRSLTE_API int rf_blade_open_multi(char *args,
|
||||
void **handler, uint32_t nof_rx_antennas);
|
||||
void **handler, uint32_t nof_channels);
|
||||
|
||||
SRSLTE_API char* rf_blade_devname(void *h);
|
||||
|
||||
|
@ -111,6 +111,16 @@ SRSLTE_API void rf_blade_get_time(void *h,
|
|||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
SRSLTE_API int rf_blade_send_timed_multi(void *h,
|
||||
void *data[4],
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
|
||||
SRSLTE_API int rf_blade_send_timed(void *h,
|
||||
void *data,
|
||||
int nsamples,
|
||||
|
|
|
@ -38,7 +38,7 @@ typedef struct {
|
|||
void (*srslte_rf_suppress_stdout)(void *h);
|
||||
void (*srslte_rf_register_error_handler)(void *h, srslte_rf_error_handler_t error_handler);
|
||||
int (*srslte_rf_open)(char *args, void **h);
|
||||
int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_rx_antennas);
|
||||
int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_channels);
|
||||
int (*srslte_rf_close)(void *h);
|
||||
void (*srslte_rf_set_master_clock_rate)(void *h, double rate);
|
||||
bool (*srslte_rf_is_master_clock_dynamic)(void *h);
|
||||
|
@ -58,6 +58,9 @@ typedef struct {
|
|||
int (*srslte_rf_send_timed)(void *h, void *data, int nsamples,
|
||||
time_t secs, double frac_secs, bool has_time_spec,
|
||||
bool blocking, bool is_start_of_burst, bool is_end_of_burst);
|
||||
int (*srslte_rf_send_timed_multi)(void *h, void *data[4], int nsamples,
|
||||
time_t secs, double frac_secs, bool has_time_spec,
|
||||
bool blocking, bool is_start_of_burst, bool is_end_of_burst);
|
||||
void (*srslte_rf_set_tx_cal)(void *h, srslte_rf_cal_t *cal);
|
||||
|
||||
void (*srslte_rf_set_rx_cal)(void *h, srslte_rf_cal_t *cal);
|
||||
|
@ -81,7 +84,7 @@ static rf_dev_t dev_uhd = {
|
|||
rf_uhd_suppress_stdout,
|
||||
rf_uhd_register_error_handler,
|
||||
rf_uhd_open,
|
||||
rf_uhd_open_multi,
|
||||
.srslte_rf_open_multi = rf_uhd_open_multi,
|
||||
rf_uhd_close,
|
||||
rf_uhd_set_master_clock_rate,
|
||||
rf_uhd_is_master_clock_dynamic,
|
||||
|
@ -97,6 +100,7 @@ static rf_dev_t dev_uhd = {
|
|||
rf_uhd_recv_with_time,
|
||||
rf_uhd_recv_with_time_multi,
|
||||
rf_uhd_send_timed,
|
||||
.srslte_rf_send_timed_multi = rf_uhd_send_timed_multi,
|
||||
rf_uhd_set_tx_cal,
|
||||
rf_uhd_set_rx_cal
|
||||
};
|
||||
|
@ -119,7 +123,7 @@ static rf_dev_t dev_blade = {
|
|||
rf_blade_suppress_stdout,
|
||||
rf_blade_register_error_handler,
|
||||
rf_blade_open,
|
||||
rf_blade_open_multi,
|
||||
.srslte_rf_open_multi = rf_blade_open_multi,
|
||||
rf_blade_close,
|
||||
rf_blade_set_master_clock_rate,
|
||||
rf_blade_is_master_clock_dynamic,
|
||||
|
@ -135,6 +139,7 @@ static rf_dev_t dev_blade = {
|
|||
rf_blade_recv_with_time,
|
||||
rf_blade_recv_with_time_multi,
|
||||
rf_blade_send_timed,
|
||||
.srslte_rf_send_timed_multi = rf_blade_send_timed_multi,
|
||||
rf_blade_set_tx_cal,
|
||||
rf_blade_set_rx_cal
|
||||
};
|
||||
|
@ -172,6 +177,7 @@ static rf_dev_t dev_soapy = {
|
|||
rf_soapy_recv_with_time,
|
||||
rf_soapy_recv_with_time_multi,
|
||||
rf_soapy_send_timed,
|
||||
.srslte_rf_send_timed_multi = /* FIXME: Implement srslte_rf_send_timed_multi for Soapy SDR */ NULL,
|
||||
rf_soapy_set_tx_cal,
|
||||
rf_soapy_set_rx_cal
|
||||
};
|
||||
|
|
|
@ -102,7 +102,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
|
|||
return srslte_rf_open_devname_multi(rf, devname, args, 1);
|
||||
}
|
||||
|
||||
int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_rx_antennas) {
|
||||
int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) {
|
||||
/* Try to open the device if name is provided */
|
||||
if (devname) {
|
||||
if (devname[0] != '\0') {
|
||||
|
@ -110,7 +110,7 @@ int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uin
|
|||
while(available_devices[i] != NULL) {
|
||||
if (!strcmp(available_devices[i]->name, devname)) {
|
||||
rf->dev = available_devices[i];
|
||||
return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas);
|
||||
return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_channels);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uin
|
|||
/* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */
|
||||
int i=0;
|
||||
while(available_devices[i] != NULL) {
|
||||
if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas)) {
|
||||
if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_channels)) {
|
||||
rf->dev = available_devices[i];
|
||||
return 0;
|
||||
}
|
||||
|
@ -301,6 +301,32 @@ int srslte_rf_send_timed3(srslte_rf_t *rf,
|
|||
has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
|
||||
}
|
||||
|
||||
int srslte_rf_send_timed_multi(srslte_rf_t *rf,
|
||||
void *data[4],
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst)
|
||||
{
|
||||
|
||||
return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, secs, frac_secs,
|
||||
true, blocking, is_start_of_burst, is_end_of_burst);
|
||||
}
|
||||
|
||||
int srslte_rf_send_multi(srslte_rf_t *rf,
|
||||
void *data[4],
|
||||
int nsamples,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst)
|
||||
{
|
||||
|
||||
return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, 0, 0,
|
||||
false, blocking, is_start_of_burst, is_end_of_burst);
|
||||
}
|
||||
|
||||
int srslte_rf_send(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking)
|
||||
{
|
||||
return srslte_rf_send2(rf, data, nsamples, blocking, true, true);
|
||||
|
|
|
@ -289,7 +289,7 @@ int rf_uhd_open(char *args, void **h)
|
|||
return rf_uhd_open_multi(args, h, 1);
|
||||
}
|
||||
|
||||
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
|
||||
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
|
||||
{
|
||||
if (h) {
|
||||
*h = NULL;
|
||||
|
@ -397,11 +397,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
|
|||
.otw_format = "sc16",
|
||||
.args = "",
|
||||
.channel_list = channel,
|
||||
.n_channels = 1
|
||||
.n_channels = nof_channels,
|
||||
};
|
||||
|
||||
handler->nof_rx_channels = nof_rx_antennas;
|
||||
handler->nof_tx_channels = 1;
|
||||
handler->nof_rx_channels = nof_channels;
|
||||
handler->nof_tx_channels = nof_channels;
|
||||
|
||||
/* Set default rate to avoid decimation warnings */
|
||||
uhd_usrp_set_rx_rate(handler->usrp, 1.92e6, 0);
|
||||
|
@ -654,8 +654,28 @@ int rf_uhd_send_timed(void *h,
|
|||
bool is_start_of_burst,
|
||||
bool is_end_of_burst)
|
||||
{
|
||||
void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem};
|
||||
|
||||
return rf_uhd_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
|
||||
}
|
||||
|
||||
int rf_uhd_send_timed_multi(void *h,
|
||||
void *data[4],
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst) {
|
||||
rf_uhd_handler_t* handler = (rf_uhd_handler_t*) h;
|
||||
|
||||
/* Resets the USRP time FIXME: this might cause problems for burst transmissions */
|
||||
if (!has_time_spec && is_start_of_burst && handler->nof_tx_channels > 1) {
|
||||
uhd_usrp_set_time_now(handler->usrp, 0, 0, 0);
|
||||
uhd_tx_metadata_set_time_spec(&handler->tx_md, 0, 0.1);
|
||||
}
|
||||
|
||||
size_t txd_samples;
|
||||
if (has_time_spec) {
|
||||
uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs);
|
||||
|
@ -663,7 +683,10 @@ int rf_uhd_send_timed(void *h,
|
|||
int trials = 0;
|
||||
if (blocking) {
|
||||
int n = 0;
|
||||
cf_t *data_c = (cf_t*) data;
|
||||
cf_t *data_c[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data_c[i] = data[i];
|
||||
}
|
||||
do {
|
||||
size_t tx_samples = handler->tx_nof_samples;
|
||||
|
||||
|
@ -681,9 +704,12 @@ int rf_uhd_send_timed(void *h,
|
|||
tx_samples = nsamples - n;
|
||||
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
|
||||
}
|
||||
|
||||
void *buff = (void*) &data_c[n];
|
||||
const void *buffs_ptr[4] = {buff, zero_mem, zero_mem, zero_mem};
|
||||
|
||||
const void *buffs_ptr[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
void *buff = (void*) &data_c[i][n];
|
||||
buffs_ptr[i] = buff;
|
||||
}
|
||||
uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr,
|
||||
tx_samples, &handler->tx_md, 3.0, &txd_samples);
|
||||
if (error) {
|
||||
|
@ -697,7 +723,10 @@ int rf_uhd_send_timed(void *h,
|
|||
} while (n < nsamples && trials < 100);
|
||||
return nsamples;
|
||||
} else {
|
||||
const void *buffs_ptr[4] = {data, zero_mem, zero_mem, zero_mem};
|
||||
const void *buffs_ptr[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
buffs_ptr[i] = data[i];
|
||||
}
|
||||
uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst);
|
||||
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
|
||||
return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples);
|
||||
|
|
|
@ -39,7 +39,7 @@ SRSLTE_API int rf_uhd_open(char *args,
|
|||
|
||||
SRSLTE_API int rf_uhd_open_multi(char *args,
|
||||
void **handler,
|
||||
uint32_t nof_rx_antennas);
|
||||
uint32_t nof_channels);
|
||||
|
||||
SRSLTE_API char* rf_uhd_devname(void *h);
|
||||
|
||||
|
@ -123,3 +123,13 @@ SRSLTE_API int rf_uhd_send_timed(void *h,
|
|||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
|
||||
SRSLTE_API int rf_uhd_send_timed_multi(void *h,
|
||||
void *data[SRSLTE_MAX_PORTS],
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
|
||||
#include "srslte/phy/ue/ue_dl.h"
|
||||
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
@ -38,21 +36,23 @@
|
|||
#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
|
||||
|
||||
|
||||
static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}; // Only TM1 and TM2 are currently supported
|
||||
const uint32_t nof_ue_formats = 2;
|
||||
const static srslte_dci_format_t ue_dci_formats[8][2] = {
|
||||
/* Mode 1 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1},
|
||||
/* Mode 2 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1},
|
||||
/* Mode 3 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2A},
|
||||
/* Mode 4 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2},
|
||||
/* Mode 5 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1D},
|
||||
/* Mode 6 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1B},
|
||||
/* Mode 7 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1},
|
||||
/* Mode 8 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2B}
|
||||
};
|
||||
|
||||
static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
|
||||
const uint32_t nof_common_formats = 2;
|
||||
|
||||
int srslte_ue_dl_init(srslte_ue_dl_t *q,
|
||||
srslte_cell_t cell)
|
||||
{
|
||||
return srslte_ue_dl_init_multi(q, cell, 1);
|
||||
}
|
||||
|
||||
int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas)
|
||||
int srslte_ue_dl_init(srslte_ue_dl_t *q,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_rx_antennas)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
|
@ -97,19 +97,28 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
|
|||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_pdsch_init_multi(&q->pdsch, q->cell, nof_rx_antennas)) {
|
||||
if (srslte_pdsch_init_rx(&q->pdsch, q->cell, nof_rx_antennas)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
if (srslte_softbuffer_rx_init(&q->softbuffer, q->cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating soft buffer\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]) {
|
||||
fprintf(stderr, "Error allocating soft buffer\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_softbuffer_rx_init(q->softbuffers[i], q->cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating soft buffer\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
if (srslte_cfo_init(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) {
|
||||
fprintf(stderr, "Error initiating SFO correct\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz);
|
||||
srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz);
|
||||
|
||||
for (int j=0;j<nof_rx_antennas;j++) {
|
||||
q->sf_symbols_m[j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t));
|
||||
|
@ -154,7 +163,12 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
|
|||
srslte_pdcch_free(&q->pdcch);
|
||||
srslte_pdsch_free(&q->pdsch);
|
||||
srslte_cfo_free(&q->sfo_correct);
|
||||
srslte_softbuffer_rx_free(&q->softbuffer);
|
||||
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
|
||||
srslte_softbuffer_rx_free(q->softbuffers[i]);
|
||||
if (q->softbuffers[i]) {
|
||||
free(q->softbuffers[i]);
|
||||
}
|
||||
}
|
||||
for (int j=0;j<q->nof_rx_antennas;j++) {
|
||||
if (q->sf_symbols_m[j]) {
|
||||
free(q->sf_symbols_m[j]);
|
||||
|
@ -188,7 +202,9 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) {
|
|||
}
|
||||
|
||||
void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
|
||||
srslte_softbuffer_rx_reset(&q->softbuffer);
|
||||
for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){
|
||||
srslte_softbuffer_rx_reset(q->softbuffers[i]);
|
||||
}
|
||||
bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
|
||||
}
|
||||
|
||||
|
@ -203,24 +219,12 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
|
|||
* - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti()
|
||||
* - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti()
|
||||
*/
|
||||
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) {
|
||||
cf_t *_input[SRSLTE_MAX_PORTS];
|
||||
_input[0] = input;
|
||||
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, q->current_rnti);
|
||||
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
||||
uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) {
|
||||
return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks);
|
||||
}
|
||||
|
||||
int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti) {
|
||||
return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti);
|
||||
}
|
||||
|
||||
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi)
|
||||
{
|
||||
cf_t *_input[SRSLTE_MAX_PORTS];
|
||||
_input[0] = input;
|
||||
return srslte_ue_dl_decode_fft_estimate_multi(q, _input, sf_idx, cfi);
|
||||
}
|
||||
|
||||
int srslte_ue_dl_decode_fft_estimate_multi(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)
|
||||
{
|
||||
if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
|
||||
|
||||
|
@ -273,29 +277,43 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c
|
|||
}
|
||||
|
||||
|
||||
int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx)
|
||||
{
|
||||
return srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx);
|
||||
int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx,
|
||||
int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type) {
|
||||
uint32_t pmi = 0;
|
||||
|
||||
/* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */
|
||||
if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
|
||||
if (grant->nof_tb == 1) {
|
||||
if (grant->pinfo > 0 && grant->pinfo < 5) {
|
||||
pmi = grant->pinfo - 1;
|
||||
} else {
|
||||
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (grant->pinfo < 2) {
|
||||
pmi = grant->pinfo;
|
||||
} else {
|
||||
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
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, uint8_t *data, uint32_t tti, uint16_t rnti)
|
||||
{
|
||||
cf_t *_input[SRSLTE_MAX_PORTS];
|
||||
_input[0] = input;
|
||||
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, rnti);
|
||||
}
|
||||
|
||||
int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti, uint16_t rnti)
|
||||
{
|
||||
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
|
||||
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti,
|
||||
bool acks[SRSLTE_MAX_CODEWORDS]) {
|
||||
srslte_mimo_type_t mimo_type;
|
||||
srslte_dci_msg_t dci_msg;
|
||||
srslte_ra_dl_dci_t dci_unpacked;
|
||||
srslte_ra_dl_grant_t grant;
|
||||
int ret = SRSLTE_ERROR;
|
||||
uint32_t cfi;
|
||||
uint32_t sf_idx = tti%10;
|
||||
|
||||
uint32_t sf_idx = tti%10;
|
||||
|
||||
if ((ret = srslte_ue_dl_decode_fft_estimate_multi(q, input, sf_idx, &cfi)) < 0) {
|
||||
if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -308,7 +326,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
|
|||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
int found_dci = srslte_ue_dl_find_dl_dci(q, cfi, sf_idx, rnti, &dci_msg);
|
||||
int found_dci = srslte_ue_dl_find_dl_dci(q, tm, cfi, sf_idx, rnti, &dci_msg);
|
||||
if (found_dci == 1) {
|
||||
|
||||
if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) {
|
||||
|
@ -319,18 +337,68 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
|
|||
/* ===== These lines of code are supposed to be MAC functionality === */
|
||||
|
||||
|
||||
uint32_t rvidx = 0;
|
||||
int rvidx[SRSLTE_MAX_CODEWORDS] = {1};
|
||||
if (dci_unpacked.rv_idx < 0) {
|
||||
uint32_t sfn = tti/10;
|
||||
uint32_t k = (sfn/2)%4;
|
||||
rvidx = ((uint32_t) ceilf((float)1.5*k))%4;
|
||||
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs);
|
||||
uint32_t k = (sfn/2)%4;
|
||||
for (int i = 0; i < grant.nof_tb; i++) {
|
||||
rvidx[i] = ((uint32_t) ceilf((float) 1.5 * k)) % 4;
|
||||
srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs);
|
||||
}
|
||||
} else {
|
||||
rvidx = dci_unpacked.rv_idx;
|
||||
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs);
|
||||
for (int i = 0; i < grant.nof_tb; i++) {
|
||||
switch(i) {
|
||||
case 0:
|
||||
rvidx[i] = (uint32_t) dci_unpacked.rv_idx;
|
||||
break;
|
||||
case 1:
|
||||
rvidx[i] = (uint32_t) dci_unpacked.rv_idx_1;
|
||||
break;
|
||||
default:
|
||||
ERROR("Wrong number of transport blocks");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs);
|
||||
}
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx)) {
|
||||
switch(dci_msg.format) {
|
||||
case SRSLTE_DCI_FORMAT1:
|
||||
case SRSLTE_DCI_FORMAT1A:
|
||||
if (q->cell.nof_ports == 1) {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
} else {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_DCI_FORMAT2:
|
||||
if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
} else {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_DCI_FORMAT2A:
|
||||
if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
} else {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_CDD;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Not implemented formats */
|
||||
case SRSLTE_DCI_FORMAT0:
|
||||
case SRSLTE_DCI_FORMAT1C:
|
||||
case SRSLTE_DCI_FORMAT1B:
|
||||
case SRSLTE_DCI_FORMAT1D:
|
||||
case SRSLTE_DCI_FORMAT2B:
|
||||
default:
|
||||
ERROR("Transmission mode not supported.");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx, mimo_type)) {
|
||||
ERROR("Configuing PDSCH");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -339,17 +407,26 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
|
|||
q->nof_detected++;
|
||||
|
||||
|
||||
if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) {
|
||||
ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, &q->softbuffer,
|
||||
q->sf_symbols_m, q->ce_m,
|
||||
noise_estimate,
|
||||
rnti, data);
|
||||
|
||||
if (q->pdsch_cfg.grant.mcs[0].mod > 0 && q->pdsch_cfg.grant.mcs[0].tbs >= 0) {
|
||||
ret = srslte_pdsch_decode(&q->pdsch, &q->pdsch_cfg, q->softbuffers,
|
||||
q->sf_symbols_m, q->ce_m,
|
||||
noise_estimate,
|
||||
rnti, data, acks);
|
||||
|
||||
for (int tb = 0; tb < q->pdsch_cfg.grant.nof_tb; tb++) {
|
||||
if (!acks[tb]) {
|
||||
q->pkt_errors++;
|
||||
}
|
||||
q->pkts_total++;
|
||||
}
|
||||
|
||||
if (ret == SRSLTE_ERROR) {
|
||||
q->pkt_errors++;
|
||||
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
|
||||
fprintf(stderr, "Error calling srslte_pdsch_decode()\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are in TM4 (Closed-Loop MIMO), compute condition number */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -361,15 +438,95 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
|
|||
|
||||
}
|
||||
|
||||
q->pkts_total++;
|
||||
|
||||
if (found_dci == 1 && ret == SRSLTE_SUCCESS) {
|
||||
return q->pdsch_cfg.grant.mcs.tbs;
|
||||
return q->pdsch_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, uint32_t *ri, uint32_t *pmi, float *current_sinr) {
|
||||
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
|
||||
float best_sinr = -INFINITY;
|
||||
uint32_t best_pmi = 0, best_ri = 0;
|
||||
|
||||
if (q->cell.nof_ports < 2 || q->nof_rx_antennas < 2) {
|
||||
/* Do nothing */
|
||||
return SRSLTE_SUCCESS;
|
||||
} else if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) {
|
||||
if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate,
|
||||
SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) {
|
||||
ERROR("SINR calculation error");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
/* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */
|
||||
for (uint32_t nof_layers = 1; nof_layers <= 2; nof_layers++) {
|
||||
float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers;
|
||||
if (_sinr > best_sinr + 0.1) {
|
||||
best_sinr = _sinr;
|
||||
best_pmi = q->pmi[nof_layers - 1];
|
||||
best_ri = nof_layers;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set RI */
|
||||
if (ri != NULL) {
|
||||
*ri = best_ri;
|
||||
}
|
||||
|
||||
/* Set PMI */
|
||||
if (pmi != NULL) {
|
||||
*pmi = best_pmi;
|
||||
}
|
||||
|
||||
/* Set current SINR */
|
||||
if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
|
||||
if (q->pdsch_cfg.nof_layers == 1) {
|
||||
*current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx];
|
||||
} else if (q->pdsch_cfg.nof_layers == 2) {
|
||||
*current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1];
|
||||
} else {
|
||||
ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print Trace */
|
||||
if (ri != NULL && pmi != NULL && current_sinr != NULL) {
|
||||
INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi,
|
||||
10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx);
|
||||
}
|
||||
} else {
|
||||
ERROR("Not implemented configuration");
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Compute the Rank Indicator (RI) by computing the condition number, valid for TM3 */
|
||||
int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint32_t *ri, float *cn) {
|
||||
float _cn;
|
||||
int ret = srslte_pdsch_cn_compute(&q->pdsch, q->ce_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), &_cn);
|
||||
|
||||
/* Set Condition number */
|
||||
if (cn) {
|
||||
*cn = _cn;
|
||||
}
|
||||
|
||||
/* Set rank indicator */
|
||||
if (!ret && ri) {
|
||||
*ri = (_cn > 3.0f)? 1:0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) {
|
||||
return q->last_location.ncce;
|
||||
}
|
||||
|
@ -447,7 +604,7 @@ int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, u
|
|||
}
|
||||
}
|
||||
|
||||
int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg)
|
||||
int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg)
|
||||
{
|
||||
srslte_rnti_type_t rnti_type;
|
||||
if (rnti == SRSLTE_SIRNTI) {
|
||||
|
@ -459,7 +616,7 @@ int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, u
|
|||
} else {
|
||||
rnti_type = SRSLTE_RNTI_USER;
|
||||
}
|
||||
return srslte_ue_dl_find_dl_dci_type(q, cfi, sf_idx, rnti, rnti_type, dci_msg);
|
||||
return srslte_ue_dl_find_dl_dci_type(q, tm, cfi, sf_idx, rnti, rnti_type, dci_msg);
|
||||
}
|
||||
|
||||
// Blind search for SI/P/RA-RNTI
|
||||
|
@ -483,12 +640,17 @@ static int find_dl_dci_type_siprarnti(srslte_ue_dl_t *q, uint32_t cfi, uint16_t
|
|||
}
|
||||
|
||||
// Blind search for C-RNTI
|
||||
static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg)
|
||||
{
|
||||
static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi,
|
||||
uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) {
|
||||
int ret = SRSLTE_SUCCESS;
|
||||
dci_blind_search_t search_space;
|
||||
dci_blind_search_t *current_ss = &search_space;
|
||||
|
||||
|
||||
if (cfi < 1 || cfi > 3) {
|
||||
ERROR("CFI must be 1 ≤ cfi ≤ 3", cfi);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Search UE-specific search space
|
||||
if (q->current_rnti == rnti) {
|
||||
current_ss = &q->current_ss_ue[cfi-1][sf_idx];
|
||||
|
@ -498,15 +660,19 @@ static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_i
|
|||
}
|
||||
|
||||
srslte_pdcch_set_cfi(&q->pdcch, cfi);
|
||||
|
||||
INFO("Searching DL C-RNTI in %d ue locations, %d formats\n", current_ss->nof_locations, nof_ue_formats);
|
||||
for (int f=0;f<nof_ue_formats;f++) {
|
||||
current_ss->format = ue_formats[f];
|
||||
|
||||
for (int f = 0; f < 2; f++) {
|
||||
srslte_dci_format_t format = ue_dci_formats[tm][f];
|
||||
|
||||
INFO("Searching DL C-RNTI %s in %d ue locations\n", srslte_dci_format_string(format),
|
||||
current_ss->nof_locations);
|
||||
|
||||
current_ss->format = format;
|
||||
if ((ret = dci_blind_search(q, current_ss, rnti, dci_msg))) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Search Format 1A in the Common SS also
|
||||
if (q->current_rnti == rnti) {
|
||||
current_ss = &q->current_ss_common[cfi-1];
|
||||
|
@ -526,13 +692,13 @@ static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_i
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx,
|
||||
int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx,
|
||||
uint16_t rnti, srslte_rnti_type_t rnti_type, srslte_dci_msg_t *dci_msg)
|
||||
{
|
||||
if (rnti_type == SRSLTE_RNTI_SI || rnti_type == SRSLTE_RNTI_PCH || rnti_type == SRSLTE_RNTI_RAR) {
|
||||
return find_dl_dci_type_siprarnti(q, cfi, rnti, dci_msg);
|
||||
} else {
|
||||
return find_dl_dci_type_crnti(q, cfi, sf_idx, rnti, dci_msg);
|
||||
return find_dl_dci_type_crnti(q, tm, cfi, sf_idx, rnti, dci_msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -585,16 +751,16 @@ void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuf
|
|||
srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce*72*sizeof(float));
|
||||
|
||||
|
||||
srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits.nof_re*sizeof(cf_t));
|
||||
srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits.nof_bits*sizeof(cf_t));
|
||||
int cb_len = q->pdsch_cfg.cb_segm.K1;
|
||||
for (int i=0;i<q->pdsch_cfg.cb_segm.C;i++) {
|
||||
srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t));
|
||||
srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t));
|
||||
int cb_len = q->pdsch_cfg.cb_segm[0].K1;
|
||||
for (int i=0;i<q->pdsch_cfg.cb_segm[0].C;i++) {
|
||||
char tmpstr[64];
|
||||
snprintf(tmpstr,64,"rmout_%d.dat",i);
|
||||
srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t));
|
||||
}
|
||||
printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi,
|
||||
q->pdsch_cfg.grant.mcs.idx, rv_idx, rnti);
|
||||
q->pdsch_cfg.grant.mcs[0].idx, rv_idx, rnti);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,11 @@ cf_t dummy_buffer1[15*2048/2];
|
|||
cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1};
|
||||
|
||||
int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, float offset_freq) {
|
||||
return srslte_ue_sync_init_file_multi(q, nof_prb, file_name, offset_time, offset_freq, 1);
|
||||
}
|
||||
|
||||
int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time,
|
||||
float offset_freq, uint32_t nof_rx_ant) {
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
|
@ -66,6 +71,7 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n
|
|||
q->file_cfo = -offset_freq;
|
||||
q->correct_cfo = true;
|
||||
q->fft_size = srslte_symbol_sz(nof_prb);
|
||||
q->nof_rx_antennas = nof_rx_ant;
|
||||
|
||||
if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
|
@ -80,12 +86,12 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n
|
|||
INFO("Offseting input file by %d samples and %.1f kHz\n", offset_time, offset_freq/1000);
|
||||
|
||||
if (offset_time) {
|
||||
cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * sizeof(cf_t));
|
||||
cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * nof_rx_ant * sizeof(cf_t));
|
||||
if (!file_offset_buffer) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time);
|
||||
srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time * nof_rx_ant);
|
||||
free(file_offset_buffer);
|
||||
}
|
||||
|
||||
|
@ -518,26 +524,27 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
|
|||
{
|
||||
|
||||
if (q->file_mode) {
|
||||
int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len);
|
||||
int n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error reading input file\n");
|
||||
return SRSLTE_ERROR;
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
if (n == 0) {
|
||||
srslte_filesource_seek(&q->file_source, 0);
|
||||
q->sf_idx = 9;
|
||||
int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len);
|
||||
q->sf_idx = 9;
|
||||
n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error reading input file\n");
|
||||
return SRSLTE_ERROR;
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
if (q->correct_cfo) {
|
||||
srslte_cfo_correct(&q->file_cfo_correct,
|
||||
input_buffer[0],
|
||||
input_buffer[0],
|
||||
q->file_cfo / 15000 / q->fft_size);
|
||||
|
||||
for (int i = 0; i < q->nof_rx_antennas; i++) {
|
||||
srslte_cfo_correct(&q->file_cfo_correct,
|
||||
input_buffer[i],
|
||||
input_buffer[i],
|
||||
q->file_cfo / 15000 / q->fft_size);
|
||||
}
|
||||
}
|
||||
q->sf_idx++;
|
||||
if (q->sf_idx == 10) {
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
/**
|
||||
*
|
||||
* \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 <complex.h>
|
||||
#include <immintrin.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "srslte/phy/utils/mat.h"
|
||||
|
||||
|
||||
/* Generic implementation for complex reciprocal */
|
||||
inline cf_t srslte_mat_cf_recip_gen(cf_t a) {
|
||||
return conjf(a) / (crealf(a) * crealf(a) + cimagf(a) * cimagf(a));
|
||||
}
|
||||
|
||||
/* Generic implementation for 2x2 determinant */
|
||||
inline cf_t srslte_mat_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11) {
|
||||
return a00 * a11 - a01 * a10;
|
||||
}
|
||||
|
||||
/* 2x2 Matrix inversion, generic implementation */
|
||||
inline void srslte_mat_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11,
|
||||
cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11) {
|
||||
cf_t div = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
|
||||
*r00 = a11 * div;
|
||||
*r01 = -a01 * div;
|
||||
*r10 = -a10 * div;
|
||||
*r11 = a00 * div;
|
||||
}
|
||||
|
||||
/* Generic implementation for Zero Forcing (ZF) solver */
|
||||
inline void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1, float norm) {
|
||||
cf_t _norm = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(h00, h01, h10, h11)) * norm;
|
||||
*x0 = (y0 * h11 - h01 * y1) * _norm;
|
||||
*x1 = (y1 * h00 - h10 * y0) * _norm;
|
||||
}
|
||||
|
||||
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1, float noise_estimate, float norm) {
|
||||
/* Create conjugated matrix */
|
||||
cf_t _h00 = conjf(h00);
|
||||
cf_t _h01 = conjf(h01);
|
||||
cf_t _h10 = conjf(h10);
|
||||
cf_t _h11 = conjf(h11);
|
||||
|
||||
/* 1. A = H' x H + No*/
|
||||
cf_t a00 = _h00 * h00 + _h10 * h10 + noise_estimate;
|
||||
cf_t a01 = _h00 * h01 + _h10 * h11;
|
||||
cf_t a10 = _h01 * h00 + _h11 * h10;
|
||||
cf_t a11 = _h01 * h01 + _h11 * h11 + noise_estimate;
|
||||
|
||||
/* 2. B = inv(H' x H + No) = inv(A) */
|
||||
cf_t b00 = a11;
|
||||
cf_t b01 = -a01;
|
||||
cf_t b10 = -a10;
|
||||
cf_t b11 = a00;
|
||||
cf_t _norm = norm * srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
|
||||
|
||||
|
||||
/* 3. W = inv(H' x H + No) x H' = B x H' */
|
||||
cf_t w00 = b00 * _h00 + b01 * _h01;
|
||||
cf_t w01 = b00 * _h10 + b01 * _h11;
|
||||
cf_t w10 = b10 * _h00 + b11 * _h01;
|
||||
cf_t w11 = b10 * _h10 + b11 * _h11;
|
||||
|
||||
/* 4. X = W x Y */
|
||||
*x0 = (y0 * w00 + y1 * w01) * _norm;
|
||||
*x1 = (y0 * w10 + y1 * w11) * _norm;
|
||||
}
|
||||
|
||||
inline float srslte_mat_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) {
|
||||
/* 1. A = H * H' (A = A') */
|
||||
float a00 =
|
||||
crealf(h00) * crealf(h00) + crealf(h01) * crealf(h01) + cimagf(h00) * cimagf(h00) + cimagf(h01) * cimagf(h01);
|
||||
cf_t a01 = h00 * conjf(h10) + h01 * conjf(h11);
|
||||
//cf_t a10 = h10*conjf(h00) + h11*conjf(h01) = conjf(a01);
|
||||
float a11 =
|
||||
crealf(h10) * crealf(h10) + crealf(h11) * crealf(h11) + cimagf(h10) * cimagf(h10) + cimagf(h11) * cimagf(h11);
|
||||
|
||||
/* 2. |H * H' - {λ0, λ1}| = 0 -> aλ² + bλ + c = 0 */
|
||||
float b = a00 + a11;
|
||||
float c = a00 * a11 - (crealf(a01) * crealf(a01) + cimagf(a01) * cimagf(a01));
|
||||
|
||||
/* 3. λ = (-b ± sqrt(b² - 4 * c))/2 */
|
||||
float sqr = sqrtf(b * b - 4.0f * c);
|
||||
float xmax = b + sqr;
|
||||
float xmin = b - sqr;
|
||||
|
||||
/* 4. κ = sqrt(λ_max / λ_min) */
|
||||
return 10 * log10f(xmax / xmin);
|
||||
}
|
||||
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
||||
/* SSE implementation for complex reciprocal */
|
||||
inline __m128 srslte_mat_cf_recip_sse(__m128 a) {
|
||||
__m128 conj = _MM_CONJ_PS(a);
|
||||
__m128 sqabs = _mm_mul_ps(a, a);
|
||||
sqabs = _mm_add_ps(_mm_movehdup_ps(sqabs), _mm_moveldup_ps(sqabs));
|
||||
|
||||
__m128 recp = _mm_rcp_ps(sqabs);
|
||||
|
||||
return _mm_mul_ps(recp, conj);
|
||||
}
|
||||
|
||||
/* SSE implementation for 2x2 determinant */
|
||||
inline __m128 srslte_mat_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11) {
|
||||
return _mm_sub_ps(_MM_PROD_PS(a00, a11), _MM_PROD_PS(a01, a10));
|
||||
}
|
||||
|
||||
/* SSE implementation for Zero Forcing (ZF) solver */
|
||||
inline void srslte_mat_2x2_zf_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11,
|
||||
__m128 *x0, __m128 *x1, float norm) {
|
||||
__m128 detmult1 = _MM_PROD_PS(h00, h11);
|
||||
__m128 detmult2 = _MM_PROD_PS(h01, h10);
|
||||
|
||||
__m128 det = _mm_sub_ps(detmult1, detmult2);
|
||||
__m128 detrec = _mm_mul_ps(srslte_mat_cf_recip_sse(det), _mm_set1_ps(norm));
|
||||
|
||||
*x0 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h11, y0), _MM_PROD_PS(h01, y1)), detrec);
|
||||
*x1 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h00, y1), _MM_PROD_PS(h10, y0)), detrec);
|
||||
}
|
||||
|
||||
/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
inline void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11,
|
||||
__m128 *x0, __m128 *x1, float noise_estimate, float norm) {
|
||||
__m128 _noise_estimate = _mm_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate);
|
||||
__m128 _norm = _mm_set1_ps(norm);
|
||||
|
||||
/* Create conjugated matrix */
|
||||
__m128 _h00 = _MM_CONJ_PS(h00);
|
||||
__m128 _h01 = _MM_CONJ_PS(h01);
|
||||
__m128 _h10 = _MM_CONJ_PS(h10);
|
||||
__m128 _h11 = _MM_CONJ_PS(h11);
|
||||
|
||||
/* 1. A = H' x H + No*/
|
||||
__m128 a00 = _mm_add_ps(_mm_add_ps(_MM_SQMOD_PS(h00), _MM_SQMOD_PS(h10)), _noise_estimate);
|
||||
__m128 a01 = _mm_add_ps(_MM_PROD_PS(_h00, h01), _MM_PROD_PS(_h10, h11));
|
||||
__m128 a10 = _mm_add_ps(_MM_PROD_PS(_h01, h00), _MM_PROD_PS(_h11, h10));
|
||||
__m128 a11 = _mm_add_ps(_mm_add_ps(_MM_SQMOD_PS(h01), _MM_SQMOD_PS(h11)), _noise_estimate);
|
||||
|
||||
/* 2. B = inv(H' x H + No) = inv(A) */
|
||||
__m128 b00 = a11;
|
||||
__m128 b01 = _mm_xor_ps(a01, _mm_set1_ps(-0.0f));
|
||||
__m128 b10 = _mm_xor_ps(a10, _mm_set1_ps(-0.0f));
|
||||
__m128 b11 = a00;
|
||||
_norm = _mm_mul_ps(_norm, srslte_mat_cf_recip_sse(srslte_mat_2x2_det_sse(a00, a01, a10, a11)));
|
||||
|
||||
|
||||
/* 3. W = inv(H' x H + No) x H' = B x H' */
|
||||
__m128 w00 = _mm_add_ps(_MM_PROD_PS(b00, _h00), _MM_PROD_PS(b01, _h01));
|
||||
__m128 w01 = _mm_add_ps(_MM_PROD_PS(b00, _h10), _MM_PROD_PS(b01, _h11));
|
||||
__m128 w10 = _mm_add_ps(_MM_PROD_PS(b10, _h00), _MM_PROD_PS(b11, _h01));
|
||||
__m128 w11 = _mm_add_ps(_MM_PROD_PS(b10, _h10), _MM_PROD_PS(b11, _h11));
|
||||
|
||||
/* 4. X = W x Y */
|
||||
*x0 = _MM_PROD_PS(_mm_add_ps(_MM_PROD_PS(y0, w00), _MM_PROD_PS(y1, w01)), _norm);
|
||||
*x1 = _MM_PROD_PS(_mm_add_ps(_MM_PROD_PS(y0, w10), _MM_PROD_PS(y1, w11)), _norm);
|
||||
}
|
||||
|
||||
#endif /* LV_HAVE_SSE */
|
||||
|
||||
#ifdef LV_HAVE_AVX
|
||||
|
||||
/* AVX implementation for complex reciprocal */
|
||||
inline __m256 srslte_mat_cf_recip_avx(__m256 a) {
|
||||
__m256 conj = _MM256_CONJ_PS(a);
|
||||
__m256 sqabs = _mm256_mul_ps(a, a);
|
||||
sqabs = _mm256_add_ps(_mm256_movehdup_ps(sqabs), _mm256_moveldup_ps(sqabs));
|
||||
|
||||
__m256 recp = _mm256_rcp_ps(sqabs);
|
||||
|
||||
return _mm256_mul_ps(recp, conj);
|
||||
}
|
||||
|
||||
/* AVX implementation for 2x2 determinant */
|
||||
inline __m256 srslte_mat_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11) {
|
||||
#ifdef LV_HAVE_FMA
|
||||
return _MM256_PROD_SUB_PS(a00, a11, _MM256_PROD_PS(a01, a10));
|
||||
#else
|
||||
return _mm256_sub_ps(_MM256_PROD_PS(a00, a11), _MM256_PROD_PS(a01, a10));
|
||||
#endif /* LV_HAVE_FMA */
|
||||
}
|
||||
|
||||
/* AVX implementation for Zero Forcing (ZF) solver */
|
||||
inline void srslte_mat_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11,
|
||||
__m256 *x0, __m256 *x1, float norm) {
|
||||
|
||||
__m256 det = srslte_mat_2x2_det_avx(h00, h01, h10, h11);
|
||||
__m256 detrec = _mm256_mul_ps(srslte_mat_cf_recip_avx(det), _mm256_set1_ps(norm));
|
||||
|
||||
#ifdef LV_HAVE_FMA
|
||||
*x0 = _MM256_PROD_PS(_MM256_PROD_SUB_PS(h11, y0, _MM256_PROD_PS(h01, y1)), detrec);
|
||||
*x1 = _MM256_PROD_PS(_MM256_PROD_SUB_PS(h00, y1, _MM256_PROD_PS(h10, y0)), detrec);
|
||||
#else
|
||||
*x0 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h11, y0), _MM256_PROD_PS(h01, y1)), detrec);
|
||||
*x1 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h00, y1), _MM256_PROD_PS(h10, y0)), detrec);
|
||||
#endif /* LV_HAVE_FMA */
|
||||
}
|
||||
|
||||
/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
inline void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11,
|
||||
__m256 *x0, __m256 *x1, float noise_estimate, float norm) {
|
||||
__m256 _noise_estimate = _mm256_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate,
|
||||
0.0f, noise_estimate, 0.0f, noise_estimate);
|
||||
__m256 _norm = _mm256_set1_ps(norm);
|
||||
|
||||
/* Create conjugated matrix */
|
||||
__m256 _h00 = _MM256_CONJ_PS(h00);
|
||||
__m256 _h01 = _MM256_CONJ_PS(h01);
|
||||
__m256 _h10 = _MM256_CONJ_PS(h10);
|
||||
__m256 _h11 = _MM256_CONJ_PS(h11);
|
||||
|
||||
/* 1. A = H' x H + No*/
|
||||
#ifdef LV_HAVE_FMA
|
||||
__m256 a00 = _MM256_SQMOD_ADD_PS(h00, h10, _noise_estimate);
|
||||
__m256 a01 = _MM256_PROD_ADD_PS(_h00, h01, _MM256_PROD_PS(_h10, h11));
|
||||
__m256 a10 = _MM256_PROD_ADD_PS(_h01, h00, _MM256_PROD_PS(_h11, h10));
|
||||
__m256 a11 = _MM256_SQMOD_ADD_PS(h01, h11, _noise_estimate);
|
||||
#else
|
||||
__m256 a00 = _mm256_add_ps(_MM256_SQMOD_PS(h00, h10), _noise_estimate);
|
||||
__m256 a01 = _mm256_add_ps(_MM256_PROD_PS(_h00, h01), _MM256_PROD_PS(_h10, h11));
|
||||
__m256 a10 = _mm256_add_ps(_MM256_PROD_PS(_h01, h00), _MM256_PROD_PS(_h11, h10));
|
||||
__m256 a11 = _mm256_add_ps(_MM256_SQMOD_PS(h01, h11), _noise_estimate);
|
||||
#endif /* LV_HAVE_FMA */
|
||||
|
||||
/* 2. B = inv(H' x H + No) = inv(A) */
|
||||
__m256 b00 = a11;
|
||||
__m256 b01 = _mm256_xor_ps(a01, _mm256_set1_ps(-0.0f));
|
||||
__m256 b10 = _mm256_xor_ps(a10, _mm256_set1_ps(-0.0f));
|
||||
__m256 b11 = a00;
|
||||
_norm = _mm256_mul_ps(_norm, srslte_mat_cf_recip_avx(srslte_mat_2x2_det_avx(a00, a01, a10, a11)));
|
||||
|
||||
|
||||
/* 3. W = inv(H' x H + No) x H' = B x H' */
|
||||
#ifdef LV_HAVE_FMA
|
||||
__m256 w00 = _MM256_PROD_ADD_PS(b00, _h00, _MM256_PROD_PS(b01, _h01));
|
||||
__m256 w01 = _MM256_PROD_ADD_PS(b00, _h10, _MM256_PROD_PS(b01, _h11));
|
||||
__m256 w10 = _MM256_PROD_ADD_PS(b10, _h00, _MM256_PROD_PS(b11, _h01));
|
||||
__m256 w11 = _MM256_PROD_ADD_PS(b10, _h10, _MM256_PROD_PS(b11, _h11));
|
||||
#else
|
||||
__m256 w00 = _mm256_add_ps(_MM256_PROD_PS(b00, _h00), _MM256_PROD_PS(b01, _h01));
|
||||
__m256 w01 = _mm256_add_ps(_MM256_PROD_PS(b00, _h10), _MM256_PROD_PS(b01, _h11));
|
||||
__m256 w10 = _mm256_add_ps(_MM256_PROD_PS(b10, _h00), _MM256_PROD_PS(b11, _h01));
|
||||
__m256 w11 = _mm256_add_ps(_MM256_PROD_PS(b10, _h10), _MM256_PROD_PS(b11, _h11));
|
||||
#endif /* LV_HAVE_FMA */
|
||||
|
||||
/* 4. X = W x Y */
|
||||
#ifdef LV_HAVE_FMA
|
||||
*x0 = _MM256_PROD_PS(_MM256_PROD_ADD_PS(y0, w00, _MM256_PROD_PS(y1, w01)), _norm);
|
||||
*x1 = _MM256_PROD_PS(_MM256_PROD_ADD_PS(y0, w10, _MM256_PROD_PS(y1, w11)), _norm);
|
||||
#else
|
||||
*x0 = _MM256_PROD_PS(_mm256_add_ps(_MM256_PROD_PS(y0, w00), _MM256_PROD_PS(y1, w01)), _norm);
|
||||
*x1 = _MM256_PROD_PS(_mm256_add_ps(_MM256_PROD_PS(y0, w10), _MM256_PROD_PS(y1, w11)), _norm);
|
||||
#endif /* LV_HAVE_FMA */
|
||||
}
|
||||
|
||||
#endif /* LV_HAVE_AVX */
|
|
@ -33,3 +33,12 @@ add_test(dft_dc dft_test -b -d) # Backwards first & handle dc internally
|
|||
add_test(dft_odd dft_test -N 255) # Odd-length
|
||||
add_test(dft_odd_dc dft_test -N 255 -b -d) # Odd-length, backwards first, handle dc
|
||||
|
||||
########################################################################
|
||||
# Algebra TEST
|
||||
########################################################################
|
||||
|
||||
add_executable(algebra_test mat_test.c)
|
||||
target_link_libraries(algebra_test srslte_phy)
|
||||
|
||||
add_test(algebra_2x2_zf_solver_test algebra_test -z)
|
||||
add_test(algebra_2x2_mmse_solver_test algebra_test -m)
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
/**
|
||||
*
|
||||
* \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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <complex.h>
|
||||
#include <stdbool.h>
|
||||
#include <immintrin.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "srslte/phy/utils/mat.h"
|
||||
|
||||
|
||||
bool zf_solver = false;
|
||||
bool mmse_solver = false;
|
||||
bool verbose = false;
|
||||
|
||||
double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) {
|
||||
if (ts_end->tv_usec > ts_start->tv_usec) {
|
||||
return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 +
|
||||
(double) ts_end->tv_usec - (double) ts_start->tv_usec;
|
||||
} else {
|
||||
return ((double) ts_end->tv_sec - (double) ts_start->tv_sec - 1) * 1000000 +
|
||||
((double) ts_end->tv_usec + 1000000) - (double) ts_start->tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
#define NOF_REPETITIONS 1000
|
||||
#define RUN_TEST(FUNCTION) /*TYPE NAME (void)*/ { \
|
||||
int i;\
|
||||
struct timeval start, end;\
|
||||
gettimeofday(&start, NULL); \
|
||||
bool ret = true; \
|
||||
for (i = 0; i < NOF_REPETITIONS; i++) {ret &= FUNCTION ();}\
|
||||
gettimeofday(&end, NULL);\
|
||||
if (verbose) printf("%32s: %s ... %6.2f us/call\n", #FUNCTION, (ret)?"Pass":"Fail", \
|
||||
elapsed_us(&start, &end)/NOF_REPETITIONS);\
|
||||
passed &= ret;\
|
||||
}
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [mzvh]\n", prog);
|
||||
printf("\t-m Test Minimum Mean Squared Error (MMSE) solver\n");
|
||||
printf("\t-z Test Zero Forcing (ZF) solver\n");
|
||||
printf("\t-v Verbose\n");
|
||||
printf("\t-h Show this message\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "mzvh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
mmse_solver = true;
|
||||
break;
|
||||
case 'z':
|
||||
zf_solver = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool test_zf_solver_gen(void) {
|
||||
cf_t x0, x1, cf_error0, cf_error1;
|
||||
float error;
|
||||
|
||||
cf_t x0_gold = RANDOM_CF();
|
||||
cf_t x1_gold = RANDOM_CF();
|
||||
cf_t h00 = RANDOM_CF();
|
||||
cf_t h01 = RANDOM_CF();
|
||||
cf_t h10 = RANDOM_CF();
|
||||
cf_t h11 = (1 - h01 * h10) / h00;
|
||||
cf_t y0 = x0_gold * h00 + x1_gold * h01;
|
||||
cf_t y1 = x0_gold * h10 + x1_gold * h11;
|
||||
|
||||
srslte_mat_2x2_zf_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 1.0f);
|
||||
|
||||
cf_error0 = x0 - x0_gold;
|
||||
cf_error1 = x1 - x1_gold;
|
||||
error = crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-6);
|
||||
}
|
||||
|
||||
bool test_mmse_solver_gen(void) {
|
||||
cf_t x0, x1, cf_error0, cf_error1;
|
||||
float error;
|
||||
|
||||
cf_t x0_gold = RANDOM_CF();
|
||||
cf_t x1_gold = RANDOM_CF();
|
||||
cf_t h00 = RANDOM_CF();
|
||||
cf_t h01 = RANDOM_CF();
|
||||
cf_t h10 = RANDOM_CF();
|
||||
cf_t h11 = (1 - h01 * h10) / h00;
|
||||
cf_t y0 = x0_gold * h00 + x1_gold * h01;
|
||||
cf_t y1 = x0_gold * h10 + x1_gold * h11;
|
||||
|
||||
srslte_mat_2x2_mmse_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 0.0f, 1.0f);
|
||||
|
||||
cf_error0 = x0 - x0_gold;
|
||||
cf_error1 = x1 - x1_gold;
|
||||
error = crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-6);
|
||||
}
|
||||
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
||||
bool test_zf_solver_sse(void) {
|
||||
cf_t cf_error0, cf_error1;
|
||||
float error = 0.0f;
|
||||
|
||||
cf_t x0_gold_1 = RANDOM_CF();
|
||||
cf_t x1_gold_1 = RANDOM_CF();
|
||||
cf_t h00_1 = RANDOM_CF();
|
||||
cf_t h01_1 = RANDOM_CF();
|
||||
cf_t h10_1 = RANDOM_CF();
|
||||
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
|
||||
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
|
||||
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
|
||||
|
||||
cf_t x0_gold_2 = RANDOM_CF();
|
||||
cf_t x1_gold_2 = RANDOM_CF();
|
||||
cf_t h00_2 = RANDOM_CF();
|
||||
cf_t h01_2 = RANDOM_CF();
|
||||
cf_t h10_2 = RANDOM_CF();
|
||||
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
|
||||
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
|
||||
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
|
||||
|
||||
__m128 _y0 = _mm_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
|
||||
__m128 _y1 = _mm_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
|
||||
|
||||
__m128 _h00 = _mm_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
|
||||
__m128 _h01 = _mm_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
|
||||
__m128 _h10 = _mm_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
|
||||
__m128 _h11 = _mm_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
|
||||
|
||||
__m128 _x0, _x1;
|
||||
|
||||
srslte_mat_2x2_zf_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f);
|
||||
|
||||
|
||||
__attribute__((aligned(128))) cf_t x0[2];
|
||||
__attribute__((aligned(128))) cf_t x1[2];
|
||||
|
||||
_mm_store_ps((float *) x0, _x0);
|
||||
_mm_store_ps((float *) x1, _x1);
|
||||
|
||||
cf_error0 = x0[1] - x0_gold_1;
|
||||
cf_error1 = x1[1] - x1_gold_1;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
cf_error0 = x0[0] - x0_gold_2;
|
||||
cf_error1 = x1[0] - x1_gold_2;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-3);
|
||||
}
|
||||
|
||||
bool test_mmse_solver_sse(void) {
|
||||
cf_t cf_error0, cf_error1;
|
||||
float error = 0.0f;
|
||||
|
||||
cf_t x0_gold_1 = RANDOM_CF();
|
||||
cf_t x1_gold_1 = RANDOM_CF();
|
||||
cf_t h00_1 = RANDOM_CF();
|
||||
cf_t h01_1 = RANDOM_CF();
|
||||
cf_t h10_1 = RANDOM_CF();
|
||||
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
|
||||
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
|
||||
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
|
||||
|
||||
cf_t x0_gold_2 = RANDOM_CF();
|
||||
cf_t x1_gold_2 = RANDOM_CF();
|
||||
cf_t h00_2 = RANDOM_CF();
|
||||
cf_t h01_2 = RANDOM_CF();
|
||||
cf_t h10_2 = RANDOM_CF();
|
||||
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
|
||||
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
|
||||
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
|
||||
|
||||
__m128 _y0 = _mm_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
|
||||
__m128 _y1 = _mm_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
|
||||
|
||||
__m128 _h00 = _mm_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
|
||||
__m128 _h01 = _mm_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
|
||||
__m128 _h10 = _mm_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
|
||||
__m128 _h11 = _mm_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
|
||||
|
||||
__m128 _x0, _x1;
|
||||
|
||||
srslte_mat_2x2_mmse_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f);
|
||||
|
||||
|
||||
__attribute__((aligned(128))) cf_t x0[2];
|
||||
__attribute__((aligned(128))) cf_t x1[2];
|
||||
|
||||
_mm_store_ps((float *) x0, _x0);
|
||||
_mm_store_ps((float *) x1, _x1);
|
||||
|
||||
cf_error0 = x0[1] - x0_gold_1;
|
||||
cf_error1 = x1[1] - x1_gold_1;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
cf_error0 = x0[0] - x0_gold_2;
|
||||
cf_error1 = x1[0] - x1_gold_2;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-3);
|
||||
}
|
||||
|
||||
#endif /* LV_HAVE_SSE */
|
||||
|
||||
#ifdef LV_HAVE_AVX
|
||||
|
||||
bool test_zf_solver_avx(void) {
|
||||
cf_t cf_error0, cf_error1;
|
||||
float error = 0.0f;
|
||||
|
||||
cf_t x0_gold_1 = RANDOM_CF();
|
||||
cf_t x1_gold_1 = RANDOM_CF();
|
||||
cf_t h00_1 = RANDOM_CF();
|
||||
cf_t h01_1 = RANDOM_CF();
|
||||
cf_t h10_1 = RANDOM_CF();
|
||||
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
|
||||
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
|
||||
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
|
||||
|
||||
cf_t x0_gold_2 = RANDOM_CF();
|
||||
cf_t x1_gold_2 = RANDOM_CF();
|
||||
cf_t h00_2 = RANDOM_CF();
|
||||
cf_t h01_2 = RANDOM_CF();
|
||||
cf_t h10_2 = RANDOM_CF();
|
||||
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
|
||||
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
|
||||
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
|
||||
|
||||
__m256 _y0 = _mm256_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2),
|
||||
cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
|
||||
__m256 _y1 = _mm256_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2),
|
||||
cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
|
||||
|
||||
__m256 _h00 = _mm256_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2),
|
||||
cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
|
||||
__m256 _h01 = _mm256_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2),
|
||||
cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
|
||||
__m256 _h10 = _mm256_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2),
|
||||
cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
|
||||
__m256 _h11 = _mm256_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2),
|
||||
cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
|
||||
|
||||
__m256 _x0, _x1;
|
||||
|
||||
srslte_mat_2x2_zf_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f);
|
||||
|
||||
|
||||
__attribute__((aligned(256))) cf_t x0[4];
|
||||
__attribute__((aligned(256))) cf_t x1[4];
|
||||
|
||||
_mm256_store_ps((float *) x0, _x0);
|
||||
_mm256_store_ps((float *) x1, _x1);
|
||||
|
||||
cf_error0 = x0[1] - x0_gold_1;
|
||||
cf_error1 = x1[1] - x1_gold_1;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
cf_error0 = x0[0] - x0_gold_2;
|
||||
cf_error1 = x1[0] - x1_gold_2;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-3);
|
||||
}
|
||||
|
||||
bool test_mmse_solver_avx(void) {
|
||||
cf_t cf_error0, cf_error1;
|
||||
float error = 0.0f;
|
||||
|
||||
cf_t x0_gold_1 = RANDOM_CF();
|
||||
cf_t x1_gold_1 = RANDOM_CF();
|
||||
cf_t h00_1 = RANDOM_CF();
|
||||
cf_t h01_1 = RANDOM_CF();
|
||||
cf_t h10_1 = RANDOM_CF();
|
||||
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
|
||||
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
|
||||
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
|
||||
|
||||
cf_t x0_gold_2 = RANDOM_CF();
|
||||
cf_t x1_gold_2 = RANDOM_CF();
|
||||
cf_t h00_2 = RANDOM_CF();
|
||||
cf_t h01_2 = RANDOM_CF();
|
||||
cf_t h10_2 = RANDOM_CF();
|
||||
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
|
||||
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
|
||||
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
|
||||
|
||||
__m256 _y0 = _mm256_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2),
|
||||
cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
|
||||
__m256 _y1 = _mm256_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2),
|
||||
cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
|
||||
|
||||
__m256 _h00 = _mm256_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2),
|
||||
cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
|
||||
__m256 _h01 = _mm256_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2),
|
||||
cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
|
||||
__m256 _h10 = _mm256_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2),
|
||||
cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
|
||||
__m256 _h11 = _mm256_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2),
|
||||
cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
|
||||
|
||||
__m256 _x0, _x1;
|
||||
|
||||
srslte_mat_2x2_mmse_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f);
|
||||
|
||||
|
||||
__attribute__((aligned(256))) cf_t x0[4];
|
||||
__attribute__((aligned(256))) cf_t x1[4];
|
||||
|
||||
_mm256_store_ps((float *) x0, _x0);
|
||||
_mm256_store_ps((float *) x1, _x1);
|
||||
|
||||
cf_error0 = x0[1] - x0_gold_1;
|
||||
cf_error1 = x1[1] - x1_gold_1;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
cf_error0 = x0[0] - x0_gold_2;
|
||||
cf_error1 = x1[0] - x1_gold_2;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-3);
|
||||
}
|
||||
|
||||
#endif /* LV_HAVE_AVX */
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bool passed = true;
|
||||
int ret = 0;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (zf_solver) {
|
||||
RUN_TEST(test_zf_solver_gen);
|
||||
|
||||
#ifdef LV_HAVE_SSE
|
||||
RUN_TEST(test_zf_solver_sse);
|
||||
#endif /* LV_HAVE_SSE */
|
||||
|
||||
#ifdef LV_HAVE_AVX
|
||||
RUN_TEST(test_zf_solver_avx);
|
||||
#endif /* LV_HAVE_AVX */
|
||||
}
|
||||
|
||||
if (mmse_solver) {
|
||||
RUN_TEST(test_mmse_solver_gen);
|
||||
|
||||
#ifdef LV_HAVE_SSE
|
||||
RUN_TEST(test_mmse_solver_sse);
|
||||
#endif /* LV_HAVE_SSE */
|
||||
|
||||
|
||||
#ifdef LV_HAVE_AVX
|
||||
RUN_TEST(test_mmse_solver_avx);
|
||||
#endif /* LV_HAVE_AVX */
|
||||
}
|
||||
|
||||
printf("%s!\n", (passed) ? "Ok" : "Failed");
|
||||
|
||||
if (!passed) {
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
}
|
|
@ -852,3 +852,24 @@ void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset,
|
|||
}
|
||||
}
|
||||
|
||||
void srs_vec_cf_cpy(cf_t *dst, cf_t *src, int len) {
|
||||
int i = 0;
|
||||
|
||||
#ifdef LV_HAVE_AVX
|
||||
for (; i < len - 3; i += 4) {
|
||||
_mm256_store_ps((float *) &dst[i], _mm256_load_ps((float *) &src[i]));
|
||||
}
|
||||
#endif /* LV_HAVE_AVX */
|
||||
#ifdef LV_HAVE_SSE
|
||||
for (; i < len - 1; i += 2) {
|
||||
_mm_store_ps((float *) &dst[i], _mm_load_ps((float *) &src[i]));
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
((__m64*) dst)[i] = ((__m64*) src)[i];
|
||||
}
|
||||
#else
|
||||
for (; i < len; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
#endif /* LV_HAVE_SSE */
|
||||
}
|
||||
|
|
|
@ -169,6 +169,8 @@ bool radio::has_rssi()
|
|||
|
||||
bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
|
||||
{
|
||||
void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros};
|
||||
|
||||
if (!tx_adv_negative) {
|
||||
srslte_timestamp_sub(&tx_time, 0, tx_adv_sec);
|
||||
} else {
|
||||
|
@ -177,11 +179,11 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
|
|||
|
||||
if (is_start_of_burst) {
|
||||
if (burst_preamble_samples != 0) {
|
||||
srslte_timestamp_t tx_time_pad;
|
||||
srslte_timestamp_t tx_time_pad;
|
||||
srslte_timestamp_copy(&tx_time_pad, &tx_time);
|
||||
srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded);
|
||||
save_trace(1, &tx_time_pad);
|
||||
srslte_rf_send_timed2(&rf_device, zeros, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, false);
|
||||
srslte_rf_send_timed_multi(&rf_device, iq_samples, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false);
|
||||
is_start_of_burst = false;
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +193,8 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
|
|||
srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate);
|
||||
|
||||
save_trace(0, &tx_time);
|
||||
int ret = srslte_rf_send_timed2(&rf_device, buffer, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, is_start_of_burst, false);
|
||||
iq_samples[0] = buffer;
|
||||
int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false);
|
||||
offset = 0;
|
||||
is_start_of_burst = false;
|
||||
if (ret > 0) {
|
||||
|
|
|
@ -637,7 +637,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
|
|||
if (LOG_THIS(rnti)) {
|
||||
uint8_t x = 0;
|
||||
uint8_t *ptr = grants[i].data;
|
||||
uint32_t len = phy_grant.mcs.tbs/8;
|
||||
uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8;
|
||||
if (!ptr) {
|
||||
ptr = &x;
|
||||
len = 1;
|
||||
|
@ -645,17 +645,18 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
|
|||
log_h->info_hex(ptr, len,
|
||||
"PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n",
|
||||
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process,
|
||||
phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, tti_tx);
|
||||
phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx);
|
||||
}
|
||||
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffer, rnti, grants[i].grant.rv_idx, sf_idx,
|
||||
grants[i].data))
|
||||
srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL};
|
||||
uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL};
|
||||
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, grants[i].grant.rv_idx, sf_idx, d))
|
||||
{
|
||||
fprintf(stderr, "Error putting PDSCH %d\n",i);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Save metrics stats
|
||||
ue_db[rnti].metrics_dl(phy_grant.mcs.idx);
|
||||
ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx);
|
||||
}
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
|
|
|
@ -84,20 +84,20 @@ public:
|
|||
harq_pid = grant.pid%N;
|
||||
}
|
||||
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
|
||||
grant.ndi = true;
|
||||
grant.ndi[0] = true;
|
||||
Info("Set NDI=1 for Temp-RNTI DL grant\n");
|
||||
last_temporal_crnti = grant.rnti;
|
||||
}
|
||||
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
|
||||
grant.ndi = true;
|
||||
grant.ndi[0] = true;
|
||||
Info("Set NDI=1 for C-RNTI DL grant\n");
|
||||
}
|
||||
proc[harq_pid].new_grant_dl(grant, action);
|
||||
} else {
|
||||
/* This is for SPS scheduling */
|
||||
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%N;
|
||||
if (grant.ndi) {
|
||||
grant.ndi = false;
|
||||
if (grant.ndi[0]) {
|
||||
grant.ndi[0] = false;
|
||||
proc[harq_pid].new_grant_dl(grant, action);
|
||||
} else {
|
||||
if (grant.is_sps_release) {
|
||||
|
@ -117,12 +117,12 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
|
||||
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
|
||||
{
|
||||
if (rnti_type == SRSLTE_RNTI_SI) {
|
||||
proc[N].tb_decoded(ack);
|
||||
proc[N].tb_decoded(ack, 0);
|
||||
} else {
|
||||
proc[harq_pid%N].tb_decoded(ack);
|
||||
proc[harq_pid%N].tb_decoded(ack, tb_idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,200 +137,238 @@ public:
|
|||
|
||||
void start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; }
|
||||
|
||||
int get_current_tbs(uint32_t harq_pid) { return proc[harq_pid%N].get_current_tbs(); }
|
||||
int get_current_tbs(uint32_t harq_pid, uint32_t tb_idx) { return proc[harq_pid%N].get_current_tbs(tb_idx); }
|
||||
|
||||
void set_si_window_start(int si_window_start_) { si_window_start = si_window_start_; }
|
||||
|
||||
float get_average_retx() { return average_retx; }
|
||||
|
||||
private:
|
||||
private:
|
||||
class dl_harq_process {
|
||||
public:
|
||||
dl_harq_process()
|
||||
{
|
||||
is_initiated = false;
|
||||
ack = false;
|
||||
bzero(&cur_grant, sizeof(Tgrant));
|
||||
dl_harq_process() : subproc(SRSLTE_MAX_TB) {
|
||||
|
||||
}
|
||||
|
||||
bool init(uint32_t pid_, dl_harq_entity *parent)
|
||||
{
|
||||
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
|
||||
Error("Error initiating soft buffer\n");
|
||||
return false;
|
||||
} else {
|
||||
pid = pid_;
|
||||
is_initiated = true;
|
||||
harq_entity = parent;
|
||||
log_h = harq_entity->log_h;
|
||||
return true;
|
||||
bool init(uint32_t pid_, dl_harq_entity *parent) {
|
||||
bool ret = true;
|
||||
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
ret &= subproc[tb].init(pid_, parent, tb);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void reset(void) {
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
subproc[tb].reset();
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
ack = false;
|
||||
payload_buffer_ptr = NULL;
|
||||
bzero(&cur_grant, sizeof(Tgrant));
|
||||
if (is_initiated) {
|
||||
srslte_softbuffer_rx_reset(&softbuffer);
|
||||
void new_grant_dl(Tgrant grant, Taction *action) {
|
||||
for (uint32_t tb = 0; tb < grant.phy_grant.dl.nof_tb; tb++) {
|
||||
subproc[tb].new_grant_dl(grant, action);
|
||||
}
|
||||
}
|
||||
|
||||
void new_grant_dl(Tgrant grant, Taction *action)
|
||||
{
|
||||
// Compute RV for BCCH when not specified in PDCCH format
|
||||
if (pid == HARQ_BCCH_PID && grant.rv == -1) {
|
||||
uint32_t k;
|
||||
if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different
|
||||
k = (grant.tti/20)%4;
|
||||
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
|
||||
} else if (grant.rv == -1) {
|
||||
k = (grant.tti-harq_entity->si_window_start)%4;
|
||||
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
|
||||
}
|
||||
}
|
||||
calc_is_new_transmission(grant);
|
||||
if (is_new_transmission) {
|
||||
ack = false;
|
||||
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
|
||||
n_retx = 0;
|
||||
}
|
||||
|
||||
// Save grant
|
||||
grant.last_ndi = cur_grant.ndi;
|
||||
grant.last_tti = cur_grant.tti;
|
||||
memcpy(&cur_grant, &grant, sizeof(Tgrant));
|
||||
|
||||
// Fill action structure
|
||||
bzero(action, sizeof(Taction));
|
||||
action->default_ack = ack;
|
||||
action->generate_ack = true;
|
||||
action->decode_enabled = false;
|
||||
|
||||
// If data has not yet been successfully decoded
|
||||
if (ack == false) {
|
||||
|
||||
// Instruct the PHY To combine the received data and attempt to decode it
|
||||
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes);
|
||||
action->payload_ptr = payload_buffer_ptr;
|
||||
if (!action->payload_ptr) {
|
||||
action->decode_enabled = false;
|
||||
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
|
||||
return;
|
||||
}
|
||||
action->decode_enabled = true;
|
||||
action->rv = cur_grant.rv;
|
||||
action->rnti = cur_grant.rnti;
|
||||
action->softbuffer = &softbuffer;
|
||||
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
|
||||
n_retx++;
|
||||
|
||||
} else {
|
||||
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
|
||||
}
|
||||
|
||||
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) {
|
||||
// Do not generate ACK
|
||||
Debug("Not generating ACK\n");
|
||||
action->generate_ack = false;
|
||||
} else {
|
||||
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
|
||||
// Postpone ACK after contention resolution is resolved
|
||||
action->generate_ack_callback = harq_entity->generate_ack_callback;
|
||||
action->generate_ack_callback_arg = harq_entity->demux_unit;
|
||||
Debug("ACK pending contention resolution\n");
|
||||
} else {
|
||||
Debug("Generating ACK\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tb_decoded(bool ack_)
|
||||
{
|
||||
ack = ack_;
|
||||
if (ack == true) {
|
||||
if (pid == HARQ_BCCH_PID) {
|
||||
if (harq_entity->pcap) {
|
||||
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
|
||||
}
|
||||
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
|
||||
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
|
||||
} else {
|
||||
if (harq_entity->pcap) {
|
||||
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
|
||||
}
|
||||
if (ack) {
|
||||
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
|
||||
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
|
||||
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
|
||||
} else {
|
||||
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
|
||||
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
|
||||
|
||||
// Compute average number of retransmissions per packet
|
||||
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
|
||||
}
|
||||
|
||||
Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
|
||||
pid, is_new_transmission?"newTX":"reTX ",
|
||||
cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO",
|
||||
cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti);
|
||||
|
||||
if (ack && pid == HARQ_BCCH_PID) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
int get_current_tbs(uint32_t tb_idx) { return subproc[tb_idx].get_current_tbs(); }
|
||||
|
||||
bool is_sps() { return false; }
|
||||
|
||||
int get_current_tbs() { return cur_grant.n_bytes*8; }
|
||||
|
||||
private:
|
||||
bool calc_is_new_transmission(Tgrant grant)
|
||||
{
|
||||
bool is_new_tb = true;
|
||||
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) ||
|
||||
pid == HARQ_BCCH_PID)
|
||||
{
|
||||
is_new_tb = false;
|
||||
}
|
||||
|
||||
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
|
||||
is_new_tb || // is new TB
|
||||
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
|
||||
{
|
||||
is_new_transmission = true;
|
||||
Debug("Set HARQ for new transmission\n");
|
||||
} else {
|
||||
is_new_transmission = false;
|
||||
Debug("Set HARQ for retransmission\n");
|
||||
}
|
||||
|
||||
return is_new_transmission;
|
||||
void tb_decoded(bool ack_, uint32_t tb_idx) {
|
||||
subproc[tb_idx].tb_decoded(ack_);
|
||||
}
|
||||
|
||||
bool is_initiated;
|
||||
dl_harq_entity *harq_entity;
|
||||
srslte::log *log_h;
|
||||
|
||||
bool is_new_transmission;
|
||||
|
||||
uint32_t pid;
|
||||
uint8_t *payload_buffer_ptr;
|
||||
bool ack;
|
||||
|
||||
uint32_t n_retx;
|
||||
|
||||
Tgrant cur_grant;
|
||||
srslte_softbuffer_rx_t softbuffer;
|
||||
private:
|
||||
class dl_tb_process {
|
||||
public:
|
||||
dl_tb_process(void) {
|
||||
is_initiated = false;
|
||||
ack = false;
|
||||
bzero(&cur_grant, sizeof(Tgrant));
|
||||
}
|
||||
|
||||
bool init(uint32_t pid_, dl_harq_entity *parent, uint32_t tb_idx) {
|
||||
tid = tb_idx;
|
||||
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
|
||||
Error("Error initiating soft buffer\n");
|
||||
return false;
|
||||
} else {
|
||||
pid = pid_;
|
||||
is_initiated = true;
|
||||
harq_entity = parent;
|
||||
log_h = harq_entity->log_h;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void reset(void) {
|
||||
ack = false;
|
||||
payload_buffer_ptr = NULL;
|
||||
bzero(&cur_grant, sizeof(Tgrant));
|
||||
if (is_initiated) {
|
||||
srslte_softbuffer_rx_reset(&softbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void new_grant_dl(Tgrant grant, Taction *action) {
|
||||
// Compute RV for BCCH when not specified in PDCCH format
|
||||
if (pid == HARQ_BCCH_PID && grant.rv[tid] == -1) {
|
||||
uint32_t k;
|
||||
if ((grant.tti / 10) % 2 == 0 && grant.tti % 10 == 5) { // This is SIB1, k is different
|
||||
k = (grant.tti / 20) % 4;
|
||||
grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4;
|
||||
} else if (grant.rv[tid] == -1) {
|
||||
k = (grant.tti - harq_entity->si_window_start) % 4;
|
||||
grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4;
|
||||
}
|
||||
}
|
||||
calc_is_new_transmission(grant);
|
||||
if (is_new_transmission) {
|
||||
ack = false;
|
||||
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8);
|
||||
n_retx = 0;
|
||||
}
|
||||
|
||||
// Save grant
|
||||
grant.last_ndi[tid] = cur_grant.ndi[tid];
|
||||
grant.last_tti = cur_grant.tti;
|
||||
memcpy(&cur_grant, &grant, sizeof(Tgrant));
|
||||
|
||||
// Fill action structure
|
||||
bzero(action, sizeof(Taction));
|
||||
action->default_ack = ack;
|
||||
action->generate_ack = true;
|
||||
action->decode_enabled = false;
|
||||
|
||||
// If data has not yet been successfully decoded
|
||||
if (!ack) {
|
||||
|
||||
// Instruct the PHY To combine the received data and attempt to decode it
|
||||
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid * SRSLTE_MAX_TB + tid,
|
||||
cur_grant.n_bytes[tid]);
|
||||
action->payload_ptr[tid] = payload_buffer_ptr;
|
||||
if (!action->payload_ptr) {
|
||||
action->decode_enabled = false;
|
||||
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]);
|
||||
return;
|
||||
}
|
||||
action->decode_enabled = true;
|
||||
action->rv[tid] = cur_grant.rv[tid];
|
||||
action->rnti = cur_grant.rnti;
|
||||
action->softbuffers[tid] = &softbuffer;
|
||||
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
|
||||
n_retx++;
|
||||
|
||||
} else {
|
||||
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
|
||||
}
|
||||
|
||||
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) {
|
||||
// Do not generate ACK
|
||||
Debug("Not generating ACK\n");
|
||||
action->generate_ack = false;
|
||||
} else {
|
||||
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && !ack) {
|
||||
// Postpone ACK after contention resolution is resolved
|
||||
action->generate_ack_callback = harq_entity->generate_ack_callback;
|
||||
action->generate_ack_callback_arg = harq_entity->demux_unit;
|
||||
Debug("ACK pending contention resolution\n");
|
||||
} else {
|
||||
Debug("Generating ACK\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tb_decoded(bool ack_) {
|
||||
ack = ack_;
|
||||
if (ack) {
|
||||
if (pid == HARQ_BCCH_PID) {
|
||||
if (harq_entity->pcap) {
|
||||
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes[tid], ack, cur_grant.tti);
|
||||
}
|
||||
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes[tid]);
|
||||
harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid],
|
||||
cur_grant.tti);
|
||||
} else {
|
||||
if (harq_entity->pcap) {
|
||||
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.rnti, ack,
|
||||
cur_grant.tti);
|
||||
}
|
||||
if (ack) {
|
||||
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
|
||||
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n",
|
||||
cur_grant.n_bytes[tid]);
|
||||
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid]);
|
||||
} else {
|
||||
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes[tid]);
|
||||
harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid],
|
||||
cur_grant.tti);
|
||||
|
||||
// Compute average number of retransmissions per packet
|
||||
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx,
|
||||
harq_entity->nof_pkts++);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
|
||||
}
|
||||
|
||||
Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
|
||||
pid, tid, is_new_transmission ? "newTX" : "reTX ",
|
||||
cur_grant.n_bytes[tid], cur_grant.rv[tid], ack ? "OK" : "KO",
|
||||
cur_grant.ndi[tid], cur_grant.last_ndi[tid], cur_grant.tti, cur_grant.last_tti);
|
||||
|
||||
if (ack && pid == HARQ_BCCH_PID) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; }
|
||||
|
||||
private:
|
||||
bool calc_is_new_transmission(Tgrant grant) {
|
||||
bool is_new_tb = true;
|
||||
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes[tid] == cur_grant.n_bytes[tid])) ||
|
||||
pid == HARQ_BCCH_PID) {
|
||||
is_new_tb = false;
|
||||
}
|
||||
|
||||
if ((grant.ndi[tid] != cur_grant.ndi[tid] && !is_new_tb) || // NDI toggled for same TB
|
||||
is_new_tb || // is new TB
|
||||
(pid == HARQ_BCCH_PID && grant.rv[tid] == 0)) // Broadcast PID and 1st TX (RV=0)
|
||||
{
|
||||
is_new_transmission = true;
|
||||
Debug("Set HARQ for new transmission\n");
|
||||
} else {
|
||||
is_new_transmission = false;
|
||||
Debug("Set HARQ for retransmission\n");
|
||||
}
|
||||
|
||||
return is_new_transmission;
|
||||
}
|
||||
|
||||
bool is_initiated;
|
||||
dl_harq_entity *harq_entity;
|
||||
srslte::log *log_h;
|
||||
|
||||
bool is_new_transmission;
|
||||
|
||||
uint32_t pid; /* HARQ Proccess ID */
|
||||
uint32_t tid; /* Transport block ID */
|
||||
uint8_t *payload_buffer_ptr;
|
||||
bool ack;
|
||||
|
||||
uint32_t n_retx;
|
||||
|
||||
Tgrant cur_grant;
|
||||
srslte_softbuffer_rx_t softbuffer;
|
||||
};
|
||||
|
||||
/* Transport blocks */
|
||||
std::vector<dl_tb_process> subproc;
|
||||
};
|
||||
|
||||
// Private members of dl_harq_entity
|
||||
|
||||
static bool generate_ack_callback(void *arg)
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action);
|
||||
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action);
|
||||
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action);
|
||||
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
|
||||
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
|
||||
void bch_decoded_ok(uint8_t *payload, uint32_t len);
|
||||
void pch_decoded_ok(uint32_t len);
|
||||
void tti_clock(uint32_t tti);
|
||||
|
|
|
@ -113,12 +113,12 @@ public:
|
|||
grant.rnti_type == SRSLTE_RNTI_RAR)
|
||||
{
|
||||
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
|
||||
grant.ndi = true;
|
||||
grant.ndi[0] = true;
|
||||
}
|
||||
run_tti(grant.tti, &grant, action);
|
||||
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
|
||||
if (grant.ndi) {
|
||||
grant.ndi = proc[pidof(grant.tti)].get_ndi();
|
||||
if (grant.ndi[0]) {
|
||||
grant.ndi[0] = proc[pidof(grant.tti)].get_ndi();
|
||||
run_tti(grant.tti, &grant, action);
|
||||
} else {
|
||||
Info("Not implemented\n");
|
||||
|
@ -208,7 +208,7 @@ private:
|
|||
|
||||
// Receive and route HARQ feedbacks
|
||||
if (grant) {
|
||||
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) ||
|
||||
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi()) ||
|
||||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
|
||||
grant->is_from_rar)
|
||||
{
|
||||
|
@ -216,8 +216,8 @@ private:
|
|||
|
||||
// Uplink grant in a RAR
|
||||
if (grant->is_from_rar) {
|
||||
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
|
||||
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
|
||||
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes[0]);
|
||||
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes[0]);
|
||||
if (pdu_ptr) {
|
||||
generate_new_tx(tti_tx, true, grant, action);
|
||||
} else {
|
||||
|
@ -227,7 +227,7 @@ private:
|
|||
// Normal UL grant
|
||||
} else {
|
||||
// Request a MAC PDU from the Multiplexing & Assemble Unit
|
||||
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid);
|
||||
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes[0], tti_tx, pid);
|
||||
if (pdu_ptr) {
|
||||
generate_new_tx(tti_tx, false, grant, action);
|
||||
} else {
|
||||
|
@ -258,7 +258,7 @@ private:
|
|||
if (grant->is_from_rar) {
|
||||
grant->rnti = harq_entity->rntis->temp_rnti;
|
||||
}
|
||||
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
|
||||
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes[0], grant->rnti, get_nof_retx(), tti_tx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ private:
|
|||
bool is_sps() { return false; }
|
||||
uint32_t last_tx_tti() { return tti_last_tx; }
|
||||
uint32_t get_nof_retx() { return current_tx_nb; }
|
||||
int get_current_tbs() { return cur_grant.n_bytes*8; }
|
||||
int get_current_tbs() { return cur_grant.n_bytes[0]*8; }
|
||||
|
||||
private:
|
||||
Tgrant cur_grant;
|
||||
|
@ -321,16 +321,16 @@ private:
|
|||
if (grant) {
|
||||
// HARQ entity requests an adaptive transmission
|
||||
if (grant->rv) {
|
||||
current_irv = irv_of_rv[grant->rv%4];
|
||||
current_irv = irv_of_rv[grant->rv[0]%4];
|
||||
}
|
||||
memcpy(&cur_grant, grant, sizeof(Tgrant));
|
||||
harq_feedback = false;
|
||||
Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
|
||||
pid, current_tx_nb, get_rv(), grant->n_bytes);
|
||||
pid, current_tx_nb, get_rv(), grant->n_bytes[0]);
|
||||
generate_tx(tti_tx, action);
|
||||
} else {
|
||||
Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
|
||||
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
|
||||
pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0]);
|
||||
// HARQ entity requests a non-adaptive transmission
|
||||
if (!harq_feedback) {
|
||||
generate_tx(tti_tx, action);
|
||||
|
@ -358,7 +358,7 @@ private:
|
|||
current_irv = 0;
|
||||
is_msg3 = is_msg3_;
|
||||
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
|
||||
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
|
||||
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], cur_grant.rnti);
|
||||
generate_tx(tti_tx, action);
|
||||
}
|
||||
}
|
||||
|
@ -370,10 +370,10 @@ private:
|
|||
current_tx_nb++;
|
||||
action->expect_ack = true;
|
||||
action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti;
|
||||
action->rv = cur_grant.rv>0?cur_grant.rv:get_rv();
|
||||
action->softbuffer = &softbuffer;
|
||||
action->rv[0] = cur_grant.rv[0]>0?cur_grant.rv[0]:get_rv();
|
||||
action->softbuffers = &softbuffer;
|
||||
action->tx_enabled = true;
|
||||
action->payload_ptr = pdu_ptr;
|
||||
action->payload_ptr[0] = pdu_ptr;
|
||||
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
|
||||
|
||||
current_irv = (current_irv+1)%4;
|
||||
|
|
|
@ -76,8 +76,15 @@ private:
|
|||
/* ... for DL */
|
||||
bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant);
|
||||
bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant);
|
||||
bool decode_phich(bool *ack);
|
||||
bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t pid);
|
||||
bool decode_phich(bool *ack);
|
||||
|
||||
int decode_pdsch(srslte_ra_dl_grant_t *grant,
|
||||
uint8_t *payload[SRSLTE_MAX_CODEWORDS],
|
||||
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
|
||||
int rv[SRSLTE_MAX_CODEWORDS],
|
||||
uint16_t rnti,
|
||||
uint32_t pid,
|
||||
bool acks[SRSLTE_MAX_CODEWORDS]);
|
||||
|
||||
/* ... for UL */
|
||||
void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer,
|
||||
|
@ -88,7 +95,7 @@ private:
|
|||
void set_uci_sr();
|
||||
void set_uci_periodic_cqi();
|
||||
void set_uci_aperiodic_cqi();
|
||||
void set_uci_ack(bool ack);
|
||||
void set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], uint32_t nof_tb);
|
||||
bool srs_is_ready_to_send();
|
||||
float set_power(float tx_power);
|
||||
void setup_tx_gain();
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace srsue {
|
|||
mac::mac() : ttisync(10240),
|
||||
timers_db((uint32_t) NOF_MAC_TIMERS),
|
||||
mux_unit(MAC_NOF_HARQ_PROC),
|
||||
demux_unit(MAC_NOF_HARQ_PROC),
|
||||
demux_unit(SRSLTE_MAX_TB*MAC_NOF_HARQ_PROC),
|
||||
pdu_process_thread(&demux_unit)
|
||||
{
|
||||
started = false;
|
||||
|
@ -255,17 +255,17 @@ void mac::pch_decoded_ok(uint32_t len)
|
|||
}
|
||||
}
|
||||
|
||||
void mac::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
|
||||
void mac::tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
|
||||
{
|
||||
if (rnti_type == SRSLTE_RNTI_RAR) {
|
||||
if (ack) {
|
||||
ra_procedure.tb_decoded_ok();
|
||||
}
|
||||
} else {
|
||||
dl_harq.tb_decoded(ack, rnti_type, harq_pid);
|
||||
dl_harq.tb_decoded(ack, tb_idx, rnti_type, harq_pid);
|
||||
if (ack) {
|
||||
pdu_process_thread.notify();
|
||||
metrics.rx_brate += dl_harq.get_current_tbs(harq_pid);
|
||||
metrics.rx_brate += dl_harq.get_current_tbs(harq_pid, tb_idx);
|
||||
} else {
|
||||
metrics.rx_errors++;
|
||||
}
|
||||
|
@ -283,12 +283,12 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::
|
|||
action->generate_ack = false;
|
||||
action->decode_enabled = true;
|
||||
srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1);
|
||||
action->payload_ptr = pch_payload_buffer;
|
||||
action->softbuffer = &pch_softbuffer;
|
||||
action->payload_ptr[0] = pch_payload_buffer;
|
||||
action->softbuffers[0] = &pch_softbuffer;
|
||||
action->rnti = grant.rnti;
|
||||
action->rv = grant.rv;
|
||||
if (grant.n_bytes > pch_payload_buffer_sz) {
|
||||
Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes, pch_payload_buffer_sz);
|
||||
action->rv[0] = grant.rv[0];
|
||||
if (grant.n_bytes[0] > pch_payload_buffer_sz) {
|
||||
Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes[0], pch_payload_buffer_sz);
|
||||
action->decode_enabled = false;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -269,23 +269,23 @@ void ra_proc::step_pdcch_setup() {
|
|||
|
||||
void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
|
||||
{
|
||||
if (grant.n_bytes < MAX_RAR_PDU_LEN) {
|
||||
if (grant.n_bytes[0] < MAX_RAR_PDU_LEN) {
|
||||
rDebug("DL grant found RA-RNTI=%d\n", ra_rnti);
|
||||
action->decode_enabled = true;
|
||||
action->default_ack = false;
|
||||
action->generate_ack = false;
|
||||
action->payload_ptr = rar_pdu_buffer;
|
||||
action->payload_ptr[0] = rar_pdu_buffer;
|
||||
action->rnti = grant.rnti;
|
||||
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
|
||||
action->rv = grant.rv;
|
||||
action->softbuffer = &softbuffer_rar;
|
||||
rar_grant_nbytes = grant.n_bytes;
|
||||
action->rv[0] = grant.rv[0];
|
||||
action->softbuffers[0] = &softbuffer_rar;
|
||||
rar_grant_nbytes = grant.n_bytes[0];
|
||||
rar_grant_tti = grant.tti;
|
||||
if (action->rv == 0) {
|
||||
if (action->rv[0] == 0) {
|
||||
srslte_softbuffer_rx_reset(&softbuffer_rar);
|
||||
}
|
||||
} else {
|
||||
rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes, MAX_RAR_PDU_LEN);
|
||||
rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes[0], MAX_RAR_PDU_LEN);
|
||||
action->decode_enabled = false;
|
||||
state = RESPONSE_ERROR;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
#ifdef ENABLE_GUI
|
||||
#include "srsgui/srsgui.h"
|
||||
#include <semaphore.h>
|
||||
#include <srslte/srslte.h>
|
||||
#include <srslte/interfaces/ue_interfaces.h>
|
||||
|
||||
void init_plots(srsue::phch_worker *worker);
|
||||
pthread_t plot_thread;
|
||||
sem_t plot_sem;
|
||||
|
@ -100,7 +103,7 @@ bool phch_worker::init_cell(srslte_cell_t cell_)
|
|||
}
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_init_multi(&ue_dl, cell, phy->args->nof_rx_ant)) {
|
||||
if (srslte_ue_dl_init(&ue_dl, cell, phy->args->nof_rx_ant)) {
|
||||
Error("Initiating UE DL\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -178,8 +181,8 @@ void phch_worker::work_imp()
|
|||
reset_uci();
|
||||
|
||||
bool dl_grant_available = false;
|
||||
bool ul_grant_available = false;
|
||||
bool dl_ack = false;
|
||||
bool ul_grant_available = false;
|
||||
bool dl_ack[SRSLTE_MAX_CODEWORDS] = {false};
|
||||
|
||||
mac_interface_phy::mac_grant_t dl_mac_grant;
|
||||
mac_interface_phy::tb_action_dl_t dl_action;
|
||||
|
@ -200,22 +203,30 @@ void phch_worker::work_imp()
|
|||
if(dl_grant_available) {
|
||||
/* Send grant to MAC and get action for this TB */
|
||||
phy->mac->new_grant_dl(dl_mac_grant, &dl_action);
|
||||
|
||||
|
||||
/* Set DL ACKs to default */
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
|
||||
dl_ack[tb] = dl_action.default_ack;
|
||||
}
|
||||
|
||||
/* Decode PDSCH if instructed to do so */
|
||||
dl_ack = dl_action.default_ack;
|
||||
if (dl_action.decode_enabled) {
|
||||
dl_ack = decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr,
|
||||
dl_action.softbuffer, dl_action.rv, dl_action.rnti,
|
||||
dl_mac_grant.pid);
|
||||
decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr,
|
||||
dl_action.softbuffers, dl_action.rv, dl_action.rnti,
|
||||
dl_mac_grant.pid, dl_ack);
|
||||
}
|
||||
if (dl_action.generate_ack_callback && dl_action.decode_enabled) {
|
||||
phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid);
|
||||
dl_ack = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg);
|
||||
Debug("Calling generate ACK callback returned=%d\n", dl_ack);
|
||||
|
||||
// NOTE: Currently hard-coded to 1st TB only
|
||||
for (uint32_t tb = 0; tb < 1; tb++) {
|
||||
phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid);
|
||||
dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg);
|
||||
Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]);
|
||||
}
|
||||
}
|
||||
Debug("dl_ack=%d, generate_ack=%d\n", dl_ack, dl_action.generate_ack);
|
||||
Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack);
|
||||
if (dl_action.generate_ack) {
|
||||
set_uci_ack(dl_ack);
|
||||
set_uci_ack(dl_ack, dl_mac_grant.phy_grant.dl.nof_tb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,8 +269,8 @@ void phch_worker::work_imp()
|
|||
/* Transmit PUSCH, PUCCH or SRS */
|
||||
bool signal_ready = false;
|
||||
if (ul_action.tx_enabled) {
|
||||
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr, ul_action.current_tx_nb,
|
||||
ul_action.softbuffer, ul_action.rv, ul_action.rnti, ul_mac_grant.is_from_rar);
|
||||
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb,
|
||||
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar);
|
||||
signal_ready = true;
|
||||
if (ul_action.expect_ack) {
|
||||
phy->set_pending_ack(tti + 8, ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
|
||||
|
@ -279,9 +290,11 @@ void phch_worker::work_imp()
|
|||
|
||||
if (dl_action.decode_enabled && !dl_action.generate_ack_callback) {
|
||||
if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH) {
|
||||
phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes);
|
||||
phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]);
|
||||
} else {
|
||||
phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid);
|
||||
for (uint32_t tb = 0; tb < dl_mac_grant.phy_grant.dl.nof_tb; tb++) {
|
||||
phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,7 +334,7 @@ bool phch_worker::extract_fft_and_pdcch_llr() {
|
|||
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS);
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_decode_fft_estimate_multi(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
|
||||
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
|
||||
Error("Getting PDCCH FFT estimate\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -370,7 +383,8 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
|
|||
|
||||
Debug("Looking for RNTI=0x%x\n", dl_rnti);
|
||||
|
||||
if (srslte_ue_dl_find_dl_dci_type(&ue_dl, cfi, tti%10, dl_rnti, type, &dci_msg) != 1) {
|
||||
if (srslte_ue_dl_find_dl_dci_type(&ue_dl, phy->config->dedicated.antenna_info_explicit_value.tx_mode, cfi, tti%10,
|
||||
dl_rnti, type, &dci_msg) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -380,13 +394,16 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
|
|||
}
|
||||
|
||||
/* Fill MAC grant structure */
|
||||
grant->ndi = dci_unpacked.ndi;
|
||||
grant->ndi[0] = dci_unpacked.ndi;
|
||||
grant->ndi[1] = dci_unpacked.ndi_1;
|
||||
grant->pid = dci_unpacked.harq_process;
|
||||
grant->n_bytes = grant->phy_grant.dl.mcs.tbs/8;
|
||||
grant->tti = tti;
|
||||
grant->rv = dci_unpacked.rv_idx;
|
||||
grant->rnti = dl_rnti;
|
||||
grant->rnti_type = type;
|
||||
grant->n_bytes[0] = grant->phy_grant.dl.mcs[0].tbs / (uint32_t) 8;
|
||||
grant->n_bytes[1] = grant->phy_grant.dl.mcs[1].tbs / (uint32_t) 8;
|
||||
grant->tti = tti;
|
||||
grant->rv[0] = dci_unpacked.rv_idx;
|
||||
grant->rv[1] = dci_unpacked.rv_idx_1;
|
||||
grant->rnti = dl_rnti;
|
||||
grant->rnti_type = type;
|
||||
grant->last_tti = 0;
|
||||
|
||||
last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl);
|
||||
|
@ -405,18 +422,77 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
|
|||
}
|
||||
}
|
||||
|
||||
bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload,
|
||||
srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t harq_pid)
|
||||
{
|
||||
int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS],
|
||||
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
|
||||
int rv[SRSLTE_MAX_CODEWORDS],
|
||||
uint16_t rnti, uint32_t harq_pid, bool acks[SRSLTE_MAX_CODEWORDS]) {
|
||||
char timestr[64];
|
||||
bool valid_config = true;
|
||||
timestr[0]='\0';
|
||||
|
||||
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
int ret = SRSLTE_SUCCESS;
|
||||
|
||||
for (uint32_t tb = 0; tb < grant->nof_tb; tb++) {
|
||||
if (rv[tb] < 0 || rv[tb] > 3) {
|
||||
valid_config = false;
|
||||
Error("Wrong RV (%d) for TB index %d", rv[tb], tb);
|
||||
}
|
||||
}
|
||||
|
||||
switch(phy->config->dedicated.antenna_info_explicit_value.tx_mode) {
|
||||
/* Implemented Tx Modes */
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_1:
|
||||
mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
break;
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_2:
|
||||
if (cell.nof_ports > 1) {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
} else {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
|
||||
}
|
||||
break;
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_3:
|
||||
if (grant->nof_tb == 1) {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
|
||||
} else if (grant->nof_tb == 2) {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_CDD;
|
||||
} else {
|
||||
Error("Wrong number of transport blocks (%d) for TM3\n", grant->nof_tb);
|
||||
valid_config = false;
|
||||
}
|
||||
break;
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_4:
|
||||
if (grant->nof_tb == 1) {
|
||||
mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
} else if (grant->nof_tb == 2) {
|
||||
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
|
||||
} else {
|
||||
Error("Wrong number of transport blocks (%d) for TM4\n", grant->nof_tb);
|
||||
valid_config = false;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Not implemented cases */
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_5:
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_6:
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_7:
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_8:
|
||||
Error("Not implemented Tx mode (%d)\n", phy->config->dedicated.antenna_info_explicit_value.tx_mode);
|
||||
break;
|
||||
|
||||
/* Error cases */
|
||||
case LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS:
|
||||
default:
|
||||
Error("Wrong Tx mode (%d)\n", phy->config->dedicated.antenna_info_explicit_value.tx_mode);
|
||||
valid_config = false;
|
||||
}
|
||||
|
||||
Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti);
|
||||
|
||||
/* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */
|
||||
if (rv >= 0 && rv <= 3) {
|
||||
if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv)) {
|
||||
if (ue_dl.pdsch_cfg.grant.mcs.mod > 0 && ue_dl.pdsch_cfg.grant.mcs.tbs >= 0) {
|
||||
if (valid_config) {
|
||||
if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv, mimo_type)) {
|
||||
if (ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) {
|
||||
|
||||
float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest);
|
||||
|
||||
|
@ -426,7 +502,7 @@ bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload,
|
|||
|
||||
/* Set decoder iterations */
|
||||
if (phy->args->pdsch_max_its > 0) {
|
||||
srslte_sch_set_max_noi(&ue_dl.pdsch.dl_sch, phy->args->pdsch_max_its);
|
||||
srslte_pdsch_set_max_noi(&ue_dl.pdsch, phy->args->pdsch_max_its);
|
||||
}
|
||||
|
||||
|
||||
|
@ -434,40 +510,39 @@ bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload,
|
|||
struct timeval t[3];
|
||||
gettimeofday(&t[1], NULL);
|
||||
#endif
|
||||
|
||||
bool ack = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffer, ue_dl.sf_symbols_m,
|
||||
ue_dl.ce_m, noise_estimate, rnti, payload) == 0;
|
||||
ret = srslte_pdsch_decode(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m,
|
||||
ue_dl.ce_m, noise_estimate, rnti, payload, acks);
|
||||
if (ret) {
|
||||
Error("Decoding PDSCH");
|
||||
}
|
||||
#ifdef LOG_EXECTIME
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec);
|
||||
#endif
|
||||
|
||||
Info("PDSCH: l_crb=%2d, harq=%d, tbs=%d, mcs=%d, rv=%d, crc=%s, snr=%.1f dB, n_iter=%d%s\n",
|
||||
grant->nof_prb, harq_pid,
|
||||
grant->mcs.tbs/8, grant->mcs.idx, rv,
|
||||
ack?"OK":"KO",
|
||||
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)),
|
||||
srslte_pdsch_last_noi(&ue_dl.pdsch),
|
||||
timestr);
|
||||
|
||||
Info("PDSCH: l_crb=%2d, harq=%d, nof_tb=%d, tbs={%d, %d}, mcs={%d, %d}, rv={%d, %d}, crc={%s, %s}, snr=%.1f dB, n_iter=%d%s\n",
|
||||
grant->nof_prb, harq_pid,
|
||||
grant->nof_tb, grant->mcs[0].tbs / 8, grant->mcs[1].tbs / 8, grant->mcs[0].idx, grant->mcs[1].idx,
|
||||
rv[0], rv[1], acks[0] ? "OK" : "KO", acks[1] ? "OK" : "KO",
|
||||
10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)),
|
||||
srslte_pdsch_last_noi(&ue_dl.pdsch),
|
||||
timestr);
|
||||
|
||||
//printf("tti=%d, cfo=%f\n", tti, cfo*15000);
|
||||
//srslte_vec_save_file("pdsch", signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
|
||||
// Store metrics
|
||||
dl_metrics.mcs = grant->mcs.idx;
|
||||
|
||||
return ack;
|
||||
dl_metrics.mcs = grant->mcs[0].idx;
|
||||
} else {
|
||||
Warning("Received grant for TBS=0\n");
|
||||
}
|
||||
} else {
|
||||
Error("Error configuring DL grant\n");
|
||||
Error("Error configuring DL grant\n");
|
||||
ret = SRSLTE_ERROR;
|
||||
}
|
||||
} else {
|
||||
Error("Error RV is not set or is invalid (%d)\n", rv);
|
||||
}
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool phch_worker::decode_phich(bool *ack)
|
||||
|
@ -564,12 +639,12 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
|
|||
}
|
||||
|
||||
if (ret) {
|
||||
grant->ndi = dci_unpacked.ndi;
|
||||
grant->ndi[0] = dci_unpacked.ndi;
|
||||
grant->pid = 0; // This is computed by MAC from TTI
|
||||
grant->n_bytes = grant->phy_grant.ul.mcs.tbs/8;
|
||||
grant->n_bytes[0] = grant->phy_grant.ul.mcs.tbs / (uint32_t) 8;
|
||||
grant->tti = tti;
|
||||
grant->rnti = ul_rnti;
|
||||
grant->rv = dci_unpacked.rv_idx;
|
||||
grant->rv[0] = dci_unpacked.rv_idx;
|
||||
if (SRSLTE_VERBOSE_ISINFO()) {
|
||||
srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb);
|
||||
}
|
||||
|
@ -585,11 +660,22 @@ void phch_worker::reset_uci()
|
|||
bzero(&uci_data, sizeof(srslte_uci_data_t));
|
||||
}
|
||||
|
||||
void phch_worker::set_uci_ack(bool ack)
|
||||
{
|
||||
uci_data.uci_ack = ack?1:0;
|
||||
uci_data.uci_ack_len = 1;
|
||||
}
|
||||
void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], uint32_t nof_tb) {
|
||||
if (nof_tb > 0) {
|
||||
uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0);
|
||||
}
|
||||
|
||||
if (nof_tb > 1) {
|
||||
uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0);
|
||||
}
|
||||
|
||||
if (nof_tb > 2) {
|
||||
Error("Number of transport blocks is not supported");
|
||||
}
|
||||
|
||||
uci_data.uci_ack_len = nof_tb;
|
||||
|
||||
}
|
||||
|
||||
void phch_worker::set_uci_sr()
|
||||
{
|
||||
|
@ -967,8 +1053,9 @@ int phch_worker::read_ce_abs(float *ce_abs) {
|
|||
|
||||
int phch_worker::read_pdsch_d(cf_t* pdsch_d)
|
||||
{
|
||||
memcpy(pdsch_d, ue_dl.pdsch.d, ue_dl.pdsch_cfg.nbits.nof_re*sizeof(cf_t));
|
||||
return ue_dl.pdsch_cfg.nbits.nof_re;
|
||||
|
||||
memcpy(pdsch_d, ue_dl.pdsch.d, ue_dl.pdsch_cfg.nbits[0].nof_re*sizeof(cf_t));
|
||||
return ue_dl.pdsch_cfg.nbits[0].nof_re;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -158,8 +158,8 @@ int rar_unpack(uint8_t *buffer, rar_msg_t *msg)
|
|||
srsue::phy my_phy;
|
||||
bool bch_decoded = false;
|
||||
|
||||
uint8_t payload[10240];
|
||||
uint8_t payload_bits[10240];
|
||||
uint8_t payload[SRSLTE_MAX_TB][10240];
|
||||
uint8_t payload_bits[SRSLTE_MAX_TB][10240];
|
||||
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00};
|
||||
|
||||
enum mac_state {RA, RAR, CONNREQUEST, CONNSETUP} state = RA;
|
||||
|
@ -168,7 +168,7 @@ uint32_t preamble_idx = 0;
|
|||
rar_msg_t rar_msg;
|
||||
|
||||
uint32_t nof_rtx_connsetup = 0;
|
||||
uint32_t rv_value[4] = {0, 2, 3, 1};
|
||||
uint32_t rv_value[4] = {0, 2, 3, 1};
|
||||
|
||||
void config_phy() {
|
||||
srsue::phy_interface_rrc::phy_cfg_t config;
|
||||
|
@ -194,8 +194,8 @@ void config_phy() {
|
|||
my_phy.configure_prach_params();
|
||||
}
|
||||
|
||||
srslte_softbuffer_rx_t softbuffer_rx;
|
||||
srslte_softbuffer_tx_t softbuffer_tx;
|
||||
srslte_softbuffer_rx_t softbuffers_rx[SRSLTE_MAX_TB];
|
||||
srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_TB];
|
||||
|
||||
uint16_t temp_c_rnti;
|
||||
|
||||
|
@ -218,7 +218,7 @@ public:
|
|||
|
||||
bool rar_rnti_set;
|
||||
|
||||
void pch_decoded_ok(uint32_t len) {}
|
||||
void pch_decoded_ok(uint32_t len) {}
|
||||
|
||||
|
||||
void tti_clock(uint32_t tti) {
|
||||
|
@ -233,19 +233,21 @@ public:
|
|||
|
||||
void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) {
|
||||
printf("New grant UL\n");
|
||||
memcpy(payload, conn_request_msg, grant.n_bytes*sizeof(uint8_t));
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) {
|
||||
memcpy(payload[tb], conn_request_msg, grant.n_bytes[tb]*sizeof(uint8_t));
|
||||
action->rv[tb] = rv_value[nof_rtx_connsetup%4];
|
||||
action->payload_ptr[tb] = payload[tb];
|
||||
if (action->rv[tb] == 0) {
|
||||
srslte_softbuffer_tx_reset(&softbuffers_tx[tb]);
|
||||
}
|
||||
}
|
||||
action->current_tx_nb = nof_rtx_connsetup;
|
||||
action->rv = rv_value[nof_rtx_connsetup%4];
|
||||
action->softbuffer = &softbuffer_tx;
|
||||
action->softbuffers = softbuffers_tx;
|
||||
action->rnti = temp_c_rnti;
|
||||
action->expect_ack = (nof_rtx_connsetup < 5)?true:false;
|
||||
action->payload_ptr = payload;
|
||||
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
|
||||
memcpy(&last_grant, &grant, sizeof(mac_grant_t));
|
||||
action->tx_enabled = true;
|
||||
if (action->rv == 0) {
|
||||
srslte_softbuffer_tx_reset(&softbuffer_tx);
|
||||
}
|
||||
my_phy.pdcch_dl_search(SRSLTE_RNTI_USER, temp_c_rnti);
|
||||
}
|
||||
|
||||
|
@ -258,17 +260,20 @@ public:
|
|||
if (!ack) {
|
||||
nof_rtx_connsetup++;
|
||||
action->current_tx_nb = nof_rtx_connsetup;
|
||||
action->rv = rv_value[nof_rtx_connsetup%4];
|
||||
action->softbuffer = &softbuffer_tx;
|
||||
action->softbuffers = softbuffers_tx;
|
||||
action->rnti = temp_c_rnti;
|
||||
action->expect_ack = true;
|
||||
memcpy(&action->phy_grant, &last_grant.phy_grant, sizeof(srslte_phy_grant_t));
|
||||
action->tx_enabled = true;
|
||||
if (action->rv == 0) {
|
||||
srslte_softbuffer_tx_reset(&softbuffer_tx);
|
||||
action->tx_enabled = true;
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) {
|
||||
action->rv[tb] = rv_value[nof_rtx_connsetup%4];
|
||||
if (action->rv[tb] == 0) {
|
||||
srslte_softbuffer_tx_reset(&softbuffers_tx[tb]);
|
||||
}
|
||||
printf("Retransmission %d (TB %d), rv=%d\n", nof_rtx_connsetup, tb, action->rv[tb]);
|
||||
|
||||
}
|
||||
printf("Retransmission %d, rv=%d\n", nof_rtx_connsetup, action->rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) {
|
||||
|
@ -279,24 +284,25 @@ public:
|
|||
} else {
|
||||
action->generate_ack = true;
|
||||
}
|
||||
action->payload_ptr = payload;
|
||||
action->rnti = grant.rnti;
|
||||
action->rnti = grant.rnti;
|
||||
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
|
||||
memcpy(&last_grant, &grant, sizeof(mac_grant_t));
|
||||
action->rv = grant.rv;
|
||||
action->softbuffer = &softbuffer_rx;
|
||||
|
||||
if (action->rv == 0) {
|
||||
srslte_softbuffer_rx_reset(&softbuffer_rx);
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) {
|
||||
action->softbuffers[tb] = &softbuffers_rx[tb];
|
||||
action->rv[tb] = grant.rv[tb];
|
||||
action->payload_ptr[tb] = payload[tb];
|
||||
if (action->rv[tb] == 0) {
|
||||
srslte_softbuffer_rx_reset(&softbuffers_rx[tb]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) {
|
||||
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) {
|
||||
if (ack) {
|
||||
if (rnti_type == SRSLTE_RNTI_RAR) {
|
||||
my_phy.pdcch_dl_search_reset();
|
||||
srslte_bit_unpack_vector(payload, payload_bits, last_grant.n_bytes*8);
|
||||
rar_unpack(payload_bits, &rar_msg);
|
||||
srslte_bit_unpack_vector(payload[tb_idx], payload_bits[tb_idx], last_grant.n_bytes[tb_idx]*8);
|
||||
rar_unpack(payload_bits[tb_idx], &rar_msg);
|
||||
if (rar_msg.RAPID == preamble_idx) {
|
||||
|
||||
printf("Received RAR at TTI: %d\n", last_grant.tti);
|
||||
|
@ -304,7 +310,7 @@ public:
|
|||
|
||||
temp_c_rnti = rar_msg.temp_c_rnti;
|
||||
|
||||
if (last_grant.n_bytes*8 > 20 + SRSLTE_RAR_GRANT_LEN) {
|
||||
if (last_grant.n_bytes[0]*8 > 20 + SRSLTE_RAR_GRANT_LEN) {
|
||||
uint8_t rar_grant[SRSLTE_RAR_GRANT_LEN];
|
||||
memcpy(rar_grant, &payload_bits[20], sizeof(uint8_t)*SRSLTE_RAR_GRANT_LEN);
|
||||
my_phy.set_rar_grant(last_grant.tti, rar_grant);
|
||||
|
@ -323,9 +329,11 @@ public:
|
|||
printf("BCH decoded\n");
|
||||
bch_decoded = true;
|
||||
srslte_cell_t cell;
|
||||
my_phy.get_current_cell(&cell);
|
||||
srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb);
|
||||
srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb);
|
||||
my_phy.get_current_cell(&cell);
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
srslte_softbuffer_rx_init(&softbuffers_rx[tb], cell.nof_prb);
|
||||
srslte_softbuffer_tx_init(&softbuffers_tx[tb], cell.nof_prb);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -87,8 +87,8 @@ bool bch_decoded = false;
|
|||
uint32_t total_pkts=0;
|
||||
uint32_t total_dci=0;
|
||||
uint32_t total_oks=0;
|
||||
uint8_t payload[1024];
|
||||
srslte_softbuffer_rx_t softbuffer;
|
||||
uint8_t payload[SRSLTE_MAX_TB][1024];
|
||||
srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_TB];
|
||||
|
||||
class rrc_dummy : public srsue::rrc_interface_phy
|
||||
{
|
||||
|
@ -118,20 +118,23 @@ public:
|
|||
|
||||
action->decode_enabled = true;
|
||||
action->default_ack = false;
|
||||
action->generate_ack = false;
|
||||
action->payload_ptr = payload;
|
||||
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
|
||||
action->rv = ((uint32_t) ceilf((float)3*((my_phy.tti_to_SFN(grant.tti)/2)%4)/2))%4;
|
||||
action->softbuffer = &softbuffer;
|
||||
action->rnti = grant.rnti;
|
||||
if (action->rv == 0) {
|
||||
srslte_softbuffer_rx_reset(&softbuffer);
|
||||
action->generate_ack = false;
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
action->payload_ptr[tb] = payload[tb];
|
||||
action->rv[tb] = ((uint32_t) ceilf((float) 3 * ((my_phy.tti_to_SFN(grant.tti) / 2) % 4) / 2)) % 4;
|
||||
if (action->rv == 0) {
|
||||
srslte_softbuffer_rx_reset(&softbuffers[tb]);
|
||||
}
|
||||
action->softbuffers[0] = &softbuffers[tb];
|
||||
}
|
||||
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
|
||||
|
||||
action->rnti = grant.rnti;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tb_decoded(bool ack, srslte_rnti_type_t rnti, uint32_t harq_pid) {
|
||||
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) {
|
||||
if (ack) {
|
||||
total_oks++;
|
||||
}
|
||||
|
@ -144,7 +147,9 @@ public:
|
|||
bch_decoded = true;
|
||||
srslte_cell_t cell;
|
||||
my_phy.get_current_cell(&cell);
|
||||
srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb);
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
srslte_softbuffer_rx_init(&softbuffers[tb], cell.nof_prb);
|
||||
}
|
||||
}
|
||||
void tti_clock(uint32_t tti) {
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ ul_freq = 2565000000
|
|||
tx_gain = 80
|
||||
rx_gain = 60
|
||||
|
||||
nof_rx_ant = 2
|
||||
#nof_rx_ant = 1
|
||||
#device_name = auto
|
||||
#device_args = auto
|
||||
#time_adv_nsamples = auto
|
||||
|
|
Loading…
Reference in New Issue