Commit 3c1405f6 authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Merge remote-tracking branch 'origin/NR_precoding_marix_at_MAC' into integration_2024_w03

parents 4aa5f3d6 c8afb25d
......@@ -76,6 +76,8 @@ static inline const char *rnti_types(nr_rnti_type_t rr)
}
#undef R
#define NR_MAX_NB_LAYERS 4 // 8
typedef enum {
nr_FR1 = 0,
nr_FR2
......
......@@ -74,17 +74,17 @@ typedef enum {
NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION= 0X89,
//RESERVED 0X8a ~ 0xff
NFAPI_NR_PHY_MSG_TYPE_PNF_PARAM_REQUEST = 0x0100,
NFAPI_NR_PHY_MSG_TYPE_PNF_PARAM_RESPONSE = 0x0101,
NFAPI_NR_PHY_MSG_TYPE_PNF_CONFIG_REQUEST= 0x0102,
NFAPI_NR_PHY_MSG_TYPE_PNF_CONFIG_RESPONSE= 0x0103,
NFAPI_NR_PHY_MSG_TYPE_PNF_START_REQUEST= 0x0104,
NFAPI_NR_PHY_MSG_TYPE_PNF_START_RESPONSE= 0x0105,
NFAPI_NR_PHY_MSG_TYPE_PNF_STOP_REQUEST= 0x0106,
NFAPI_NR_PHY_MSG_TYPE_PNF_STOP_RESPONSE= 0x0107,
NFAPI_NR_PHY_MSG_TYPE_PNF_PARAM_RESPONSE = 0x0101,
NFAPI_NR_PHY_MSG_TYPE_PNF_CONFIG_REQUEST= 0x0102,
NFAPI_NR_PHY_MSG_TYPE_PNF_CONFIG_RESPONSE= 0x0103,
NFAPI_NR_PHY_MSG_TYPE_PNF_START_REQUEST= 0x0104,
NFAPI_NR_PHY_MSG_TYPE_PNF_START_RESPONSE= 0x0105,
NFAPI_NR_PHY_MSG_TYPE_PNF_STOP_REQUEST= 0x0106,
NFAPI_NR_PHY_MSG_TYPE_PNF_STOP_RESPONSE= 0x0107,
NFAPI_NR_PHY_MSG_TYPE_UL_NODE_SYNC = 0x0180,
NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC,
NFAPI_NR_PHY_MSG_TYPE_TIMING_INFO
NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC,
NFAPI_NR_PHY_MSG_TYPE_TIMING_INFO
} nfapi_nr_phy_msg_type_e;
// SCF222_5G-FAPI_PHY_SPI_Specificayion.pdf Section 3.3
......@@ -449,6 +449,26 @@ typedef struct
} nfapi_nr_measurement_config_t;
// Table 3–62 Precoding matrix (PM) PDU (v.222.10.04)
typedef struct {
int16_t precoder_weight_Re;
int16_t precoder_weight_Im;
} nfapi_nr_pm_weights_t;
typedef struct {
uint16_t pm_idx;
uint16_t numLayers;
uint16_t num_ant_ports;
nfapi_nr_pm_weights_t weights[4][4]; // TODO temporary hardcoding
} nfapi_nr_pm_pdu_t;
typedef struct {
uint16_t num_pm_idx;
nfapi_nr_pm_pdu_t *pmi_pdu;
} nfapi_nr_pm_list_t;
// ERROR enums
typedef enum { // Table 2-22
NFAPI_NR_PARAM_MSG_OK = 0,
......@@ -560,6 +580,7 @@ typedef struct {
nfapi_nr_tdd_table_t tdd_table;
nfapi_nr_measurement_config_t measurement_config;
nfapi_nr_nfapi_t nfapi_config;
nfapi_nr_pm_list_t pmi_list;
} nfapi_nr_config_request_scf_t;
......@@ -592,24 +613,24 @@ typedef struct {
//3.3.4 STOP
typedef struct {
nfapi_p4_p5_message_header_t header;
nfapi_vendor_extension_tlv_t vendor_extension;
nfapi_p4_p5_message_header_t header;
nfapi_vendor_extension_tlv_t vendor_extension;
} nfapi_nr_stop_request_t;
typedef struct {
nfapi_p4_p5_message_header_t header;
nfapi_vendor_extension_tlv_t vendor_extension;
nfapi_p4_p5_message_header_t header;
nfapi_vendor_extension_tlv_t vendor_extension;
} nfapi_nr_stop_indication_t;
typedef enum {
NFAPI_NR_STOP_MSG_INVALID_STATE
NFAPI_NR_STOP_MSG_INVALID_STATE
} nfapi_nr_stop_errors_e;
//3.3.5 PHY Notifications
typedef enum {
NFAPI_NR_PHY_API_MSG_OK =0x0,
NFAPI_NR_PHY_API_MSG_INVALID_STATE =0x1,
NFAPI_NR_PHY_API_MSG_INVALID_STATE =0x1,
NFAPI_NR_PHY_API_MSG_INVALID_CONFIG =0x2,
NFAPI_NR_PHY_API_SFN_OUT_OF_SYNC =0X3,
NFAPI_NR_PHY_API_MSG_SLOR_ERR =0X4,
......@@ -620,7 +641,7 @@ typedef enum {
} nfapi_nr_phy_notifications_errors_e;
typedef struct {
uint16_t sfn; //0~1023
uint16_t sfn; //0~1023
uint16_t slot;//0~319
nfapi_nr_phy_msg_type_e msg_id;//Indicate which message received by the PHY has an error. Values taken from Table 3-4.
nfapi_nr_phy_notifications_errors_e error_code;
......@@ -632,42 +653,22 @@ typedef struct {
//table 3-32
//?
typedef struct {
uint16_t beam_idx; //0~65535
uint16_t beam_idx; //0~65535
} nfapi_nr_dig_beam_t;
typedef struct {
uint16_t dig_beam_weight_Re;
uint16_t dig_beam_weight_Re;
uint16_t dig_beam_weight_Im;
} nfapi_nr_txru_t;
typedef struct {
uint16_t num_dig_beams; //0~65535
uint16_t num_dig_beams; //0~65535
uint16_t num_txrus; //0~65535
nfapi_nr_dig_beam_t* dig_beam_list;
nfapi_nr_txru_t* txru_list;
} nfapi_nr_dbt_pdu_t;
//table 3-33
//?
typedef struct {
uint16_t num_ant_ports;
int16_t precoder_weight_Re;
int16_t precoder_weight_Im;
} nfapi_nr_num_ant_ports_t;
typedef struct {
uint16_t numLayers; //0~65535
nfapi_nr_num_ant_ports_t* num_ant_ports_list;
} nfapi_nr_num_layers_t;
typedef struct {
uint16_t pm_idx; //0~65535
nfapi_nr_num_layers_t* num_layers_list; //0~65535
//nfapi_nr_num_ant_ports_t* num_ant_ports_list;
} nfapi_nr_pm_pdu_t;
// Section 3.4
// Section 3.4.1 slot indication
......@@ -678,7 +679,7 @@ typedef struct {
typedef struct {
nfapi_p7_message_header_t header;
uint16_t sfn; //0->1023
uint16_t sfn; //0->1023
uint16_t slot;//0->319
} nfapi_nr_slot_indication_scf_t;
......@@ -1441,7 +1442,7 @@ typedef struct {
//3.4.5 slot_errors
typedef enum {
NFAPI_NR_SLOT_UL_TTI_MSG_INVALID_STATE,
NFAPI_NR_SLOT_UL_TTI_MSG_INVALID_STATE,
NFAPI_NR_SLOT_UL_TTI_SFN_OUT_OF_SYNC,
NFAPI_NR_SLOT_UL_TTI_MSG_BCH_MISSING,
NFAPI_NR_SLOT_UL_TTI_MSG_SLOT_ERR
......@@ -1449,14 +1450,14 @@ typedef enum {
} nfapi_nr_slot_errors_ul_tti_e;
typedef enum {
NFAPI_NR_SLOT_DL_TTI_MSG_INVALID_STATE,
NFAPI_NR_SLOT_DL_TTI_MSG_INVALID_STATE,
NFAPI_NR_SLOT_DL_TTI_MSG_SLOT_ERR
} nfapi_nr_slot_errors_dl_tti_e;
typedef enum {
NFAPI_NR_SLOT_UL_DCI_MSG_INVALID_STATE,
NFAPI_NR_SLOT_UL_DCI_MSG_INVALID_STATE,
NFAPI_NR_SLOT_UL_DCI_MSG_INVALID_SFN,
NFAPI_NR_SLOT_UL_DCI_MSG_UL_DCI_ERR
......
......@@ -99,408 +99,6 @@ void reset_active_stats(PHY_VARS_gNB *gNB, int frame)
}
}
int init_codebook_gNB(PHY_VARS_gNB *gNB) {
if(gNB->frame_parms.nb_antennas_tx>1){
int CSI_RS_antenna_ports = gNB->frame_parms.nb_antennas_tx;
//NR Codebook Generation for codebook type1 SinglePanel
int N1 = gNB->ap_N1;
int N2 = gNB->ap_N2;
//Uniform Planner Array: UPA
// X X X X ... X
// X X X X ... X
// N2 . . . . ... .
// X X X X ... X
// |<-----N1---->|
int x_polarization = gNB->ap_XP;
//Get the uniform planar array parameters
// To be confirmed
int O2 = N2 > 1? 4 : 1; //Vertical beam oversampling (1 or 4)
int O1 = CSI_RS_antenna_ports > 2 ? 4 : 1; //Horizontal beam oversampling (1 or 4)
AssertFatal(CSI_RS_antenna_ports == N1*N2*x_polarization,
"Nb of antenna ports at PHY %d does not correspond to what passed down with fapi %d\n",
N1*N2*x_polarization, CSI_RS_antenna_ports);
// Generation of codebook Type1 with codebookMode 1 (CSI_RS_antenna_ports < 16)
if (CSI_RS_antenna_ports < 16) {
//Generate DFT vertical beams
//ll: index of a vertical beams vector (represented by i1_1 in TS 38.214)
double complex v[N1*O1][N1];
for (int ll=0; ll<N1*O1; ll++) { //i1_1
for (int nn=0; nn<N1; nn++) {
v[ll][nn] = cexp(I*(2*M_PI*nn*ll)/(N1*O1));
//printf("v[%d][%d] = %f +j %f\n", ll,nn, creal(v[ll][nn]),cimag(v[ll][nn]));
}
}
//Generate DFT Horizontal beams
//mm: index of a Horizontal beams vector (represented by i1_2 in TS 38.214)
double complex u[N2*O2][N2];
for (int mm=0; mm<N2*O2; mm++) { //i1_2
for (int nn=0; nn<N2; nn++) {
u[mm][nn] = cexp(I*(2*M_PI*nn*mm)/(N2*O2));
//printf("u[%d][%d] = %f +j %f\n", mm,nn, creal(u[mm][nn]),cimag(u[mm][nn]));
}
}
//Generate co-phasing angles
//i_2: index of a co-phasing vector
//i1_1, i1_2, and i_2 are reported from UEs
double complex theta_n[4];
for (int nn=0; nn<4; nn++) {
theta_n[nn] = cexp(I*M_PI*nn/2);
//printf("theta_n[%d] = %f +j %f\n", nn, creal(theta_n[nn]),cimag(theta_n[nn]));
}
//Kronecker product v_lm
double complex v_lm[N1*O1][N2*O2][N2*N1];
//v_ll_mm_codebook denotes the elements of a precoding matrix W_i1,1_i_1,2
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn1=0; nn1<N1; nn1++) {
for (int nn2=0; nn2<N2; nn2++) {
//printf("indx %d \n",nn1*N2+nn2);
v_lm[ll][mm][nn1*N2+nn2] = v[ll][nn1]*u[mm][nn2];
//printf("v_lm[%d][%d][%d] = %f +j %f\n",ll,mm, nn1*N2+nn2, creal(v_lm[ll][mm][nn1*N2+nn2]),cimag(v_lm[ll][mm][nn1*N2+nn2]));
}
}
}
}
int max_mimo_layers = (CSI_RS_antenna_ports<NR_MAX_NB_LAYERS) ? CSI_RS_antenna_ports : NR_MAX_NB_LAYERS;
gNB->nr_mimo_precoding_matrix = (int32_t ***)malloc16(max_mimo_layers * sizeof(int32_t **));
int32_t ***mat = gNB->nr_mimo_precoding_matrix;
double complex res_code;
//Table 5.2.2.2.1-5:
//Codebook for 1-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
gNB->pmiq_size[0] = N1*O1*N2*O2*4+1;
mat[0] = (int32_t **)malloc16(gNB->pmiq_size[0]*sizeof(int32_t *));
//pmi=0 corresponds to unit matrix
mat[0][0] = (int32_t *)calloc(2*N1*N2,sizeof(int32_t));
for(int j_col=0; j_col<1; j_col++) { //1 layer
for (int i_rows=0; i_rows<2*N1*N2; i_rows++) { //2-x polarized antenna
if(j_col==i_rows) {
mat[0][0][i_rows+j_col] = 0x7fff;
}
}
}
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn=0; nn<4; nn++) {
int pmiq = 1+ll*N2*O2*4+mm*4+nn;
mat[0][pmiq] = (int32_t *)malloc16((2*N1*N2)*1*sizeof(int32_t));
LOG_D(PHY, "layer 1 Codebook pmiq = %d\n",pmiq);
for (int len=0; len<N1*N2; len++) {
res_code=sqrt(1/(double)CSI_RS_antenna_ports)*v_lm[ll][mm][len];
if (creal(res_code)>0)
((short*) &mat[0][pmiq][len])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[0][pmiq][len])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[0][pmiq][len])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[0][pmiq][len])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "1 Layer Precoding Matrix[0][pmi %d][antPort %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, len, creal(res_code), cimag(res_code),((short*) &mat[0][pmiq][len])[0],((short*) &mat[0][pmiq][len])[1]);
}
for(int len=N1*N2; len<2*N1*N2; len++) {
res_code=sqrt(1/(double)CSI_RS_antenna_ports)*theta_n[nn]*v_lm[ll][mm][len-N1*N2];
if (creal(res_code)>0)
((short*) &mat[0][pmiq][len])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[0][pmiq][len])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[0][pmiq][len])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[0][pmiq][len])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "1 Layer Precoding Matrix[0][pmi %d][antPort %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, len, creal(res_code), cimag(res_code),((short*) &mat[0][pmiq][len])[0],((short*) &mat[0][pmiq][len])[1]);
}
}
}
}
int llc = 0;
int mmc = 0;
double complex phase_sign = 0;
//Table 5.2.2.2.1-6:
//Codebook for 2-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
//Compute the code book size for generating 2 layers out of Tx antenna ports
//pmi_size is computed as follows
gNB->pmiq_size[1] = 1;//1 for unity matrix
for(int llb=0; llb<N1*O1; llb++) { //i_1_1
for (int mmb=0; mmb<N2*O2; mmb++) { //i_1_2
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn=0; nn<2; nn++) {
if((llb != ll) || (mmb != mm) || ((N1 == 1) && (N2 == 1))) gNB->pmiq_size[1] += 1;
}
}
}
}
}
mat[1] = (int32_t **)malloc16(gNB->pmiq_size[1]*sizeof(int32_t *));
//pmi=0 corresponds to unit matrix
mat[1][0] = (int32_t *)calloc((2*N1*N2)*(2),sizeof(int32_t));
for(int j_col=0; j_col<2; j_col++) { //2 layers
for (int i_rows=0; i_rows<2*N1*N2; i_rows++) { //2-x polarized antenna
if(j_col==i_rows) {
mat[1][0][i_rows*2+j_col] = 0x7fff;
}
}
}
//pmi=1,...,pmi_size, we construct
int pmiq = 0;
for(int llb=0; llb<N1*O1; llb++) { //i_1_1
for (int mmb=0; mmb<N2*O2; mmb++) { //i_1_2
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn=0; nn<2; nn++) {
if((llb != ll) || (mmb != mm) || ((N1 == 1) && (N2 == 1))){
pmiq += 1;
mat[1][pmiq] = (int32_t *)malloc16((2*N1*N2)*(2)*sizeof(int32_t));
LOG_D(PHY, "layer 2 Codebook pmiq = %d\n",pmiq);
for(int j_col=0; j_col<2; j_col++) {
if (j_col==0) {
llc = llb;
mmc = mmb;
phase_sign = 1;
}
if (j_col==1) {
llc = ll;
mmc = mm;
phase_sign = -1;
}
for (int i_rows=0; i_rows<N1*N2; i_rows++) {
res_code=sqrt(1/(double)(2*CSI_RS_antenna_ports))*v_lm[llc][mmc][i_rows];
if (creal(res_code)>0)
((short*) &mat[1][pmiq][i_rows*2+j_col])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[1][pmiq][i_rows*2+j_col])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[1][pmiq][i_rows*2+j_col])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[1][pmiq][i_rows*2+j_col])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "2 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq,i_rows,j_col, creal(res_code), cimag(res_code),((short*) &mat[1][pmiq][i_rows*2+j_col])[0],((short*) &mat[1][pmiq][i_rows*2+j_col])[1]);
}
for (int i_rows=N1*N2; i_rows<2*N1*N2; i_rows++) {
res_code=sqrt(1/(double)(2*CSI_RS_antenna_ports))*(phase_sign)*theta_n[nn]*v_lm[llc][mmc][i_rows-N1*N2];
if (creal(res_code)>0)
((short*) &mat[1][pmiq][i_rows*2+j_col])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[1][pmiq][i_rows*2+j_col])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[1][pmiq][i_rows*2+j_col])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[1][pmiq][i_rows*2+j_col])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "2 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq,i_rows,j_col, creal(res_code), cimag(res_code),((short*) &mat[1][pmiq][i_rows*2+j_col])[0],((short*) &mat[1][pmiq][i_rows*2+j_col])[1]);
}
}
}
}
}
}
}
}
//Table 5.2.2.2.1-7:
//Codebook for 3-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
if(max_mimo_layers>=3) {
//pmi_size is computed as follows
gNB->pmiq_size[2] = 1;//unity matrix
for(int llb=0; llb<N1*O1; llb++) { //i_1_1
for (int mmb=0; mmb<N2*O2; mmb++) { //i_1_2
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn=0; nn<2; nn++) {
if((llb != ll) || (mmb != mm)) gNB->pmiq_size[2] += 1;
}
}
}
}
}
mat[2] = (int32_t **)malloc16(gNB->pmiq_size[2]*sizeof(int32_t *));
//pmi=0 corresponds to unit matrix
mat[2][0] = (int32_t *)calloc((2*N1*N2)*(3),sizeof(int32_t));
for(int j_col=0; j_col<3; j_col++) { //3 layers
for (int i_rows=0; i_rows<2*N1*N2; i_rows++) { //2-x polarized antenna
if(j_col==i_rows) {
mat[2][0][i_rows*3+j_col] = 0x7fff;
}
}
}
pmiq = 0;
//pmi=1,...,pmi_size are computed as follows
for(int llb=0; llb<N1*O1; llb++) { //i_1_1
for (int mmb=0; mmb<N2*O2; mmb++) { //i_1_2
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn=0; nn<2; nn++) {
if((llb != ll) || (mmb != mm)){
pmiq += 1;
mat[2][pmiq] = (int32_t *)malloc16((2*N1*N2)*(3)*sizeof(int32_t));
LOG_D(PHY, "layer 3 Codebook pmiq = %d\n",pmiq);
for(int j_col=0; j_col<3; j_col++) {
if (j_col==0) {
llc = llb;
mmc = mmb;
phase_sign = 1;
}
if (j_col==1) {
llc = ll;
mmc = mm;
phase_sign = 1;
}
if (j_col==2) {
llc = ll;
mmc = mm;
phase_sign = -1;
}
for (int i_rows=0; i_rows<N1*N2; i_rows++) {
res_code=sqrt(1/(double)(3*CSI_RS_antenna_ports))*v_lm[llc][mmc][i_rows];
if (creal(res_code)>0)
((short*) &mat[2][pmiq][i_rows*3+j_col])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[2][pmiq][i_rows*3+j_col])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[2][pmiq][i_rows*3+j_col])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[2][pmiq][i_rows*3+j_col])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "3 Layer Precoding Matrix[2][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq,i_rows,j_col, creal(res_code), cimag(res_code),((short*) &mat[2][pmiq][i_rows*3+j_col])[0],((short*) &mat[2][pmiq][i_rows*3+j_col])[1]);
}
for (int i_rows=N1*N2; i_rows<2*N1*N2; i_rows++) {
res_code=sqrt(1/(double)(3*CSI_RS_antenna_ports))*(phase_sign)*theta_n[nn]*v_lm[llc][mmc][i_rows-N1*N2];
if (creal(res_code)>0)
((short*) &mat[2][pmiq][i_rows*3+j_col])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[2][pmiq][i_rows*3+j_col])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[2][pmiq][i_rows*3+j_col])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[2][pmiq][i_rows*3+j_col])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "3 Layer Precoding Matrix[2][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq,i_rows,j_col, creal(res_code), cimag(res_code),((short*) &mat[2][pmiq][i_rows*3+j_col])[0],((short*) &mat[2][pmiq][i_rows*3+j_col])[1]);
}
}
}
}
}
}
}
}
}
//Table 5.2.2.2.1-8:
//Codebook for 4-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
if(max_mimo_layers>=4) {
//pmi_size is computed as follows
gNB->pmiq_size[3] = 1;//unity matrix
for(int llb=0; llb<N1*O1; llb++) { //i_1_1
for (int mmb=0; mmb<N2*O2; mmb++) { //i_1_2
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn=0; nn<2; nn++) {
if((llb != ll) || (mmb != mm)) gNB->pmiq_size[3] += 1;
}
}
}
}
}
mat[3] = (int32_t **)malloc16(gNB->pmiq_size[3]*sizeof(int32_t *));
//pmi=0 corresponds to unit matrix
mat[3][0] = (int32_t *)calloc((2*N1*N2)*(4),sizeof(int32_t));
for(int j_col=0; j_col<4; j_col++) { //4 layers
for (int i_rows=0; i_rows<2*N1*N2; i_rows++) { //2-x polarized antenna
if(j_col==i_rows) {
mat[3][0][i_rows*4+j_col] = 0x7fff;
}
}
}
pmiq = 0;
//pmi=1,...,pmi_size are computed as follows
for(int llb=0; llb<N1*O1; llb++) { //i_1_1
for (int mmb=0; mmb<N2*O2; mmb++) { //i_1_2
for(int ll=0; ll<N1*O1; ll++) { //i_1_1
for (int mm=0; mm<N2*O2; mm++) { //i_1_2
for (int nn=0; nn<2; nn++) {
if((llb != ll) || (mmb != mm)){
pmiq += 1;
mat[3][pmiq] = (int32_t *)malloc16((2*N1*N2)*4*sizeof(int32_t));
LOG_D(PHY, "layer 4 pmiq = %d\n",pmiq);
for(int j_col=0; j_col<4; j_col++) {
if (j_col==0) {
llc = llb;
mmc = mmb;
phase_sign = 1;
}
if (j_col==1) {
llc = ll;
mmc = mm;
phase_sign = 1;
}
if (j_col==2) {
llc = llb;
mmc = mmb;
phase_sign = -1;
}
if (j_col==3) {
llc = ll;
mmc = mm;
phase_sign = -1;
}
for (int i_rows=0; i_rows<N1*N2; i_rows++) {
res_code=sqrt(1/(double)(4*CSI_RS_antenna_ports))*v_lm[llc][mmc][i_rows];
if (creal(res_code)>0)
((short*) &mat[3][pmiq][i_rows*4+j_col])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[3][pmiq][i_rows*4+j_col])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[3][pmiq][i_rows*4+j_col])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[3][pmiq][i_rows*4+j_col])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "4 Layer Precoding Matrix[3][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq,i_rows,j_col, creal(res_code), cimag(res_code),((short*) &mat[3][pmiq][i_rows*4+j_col])[0],((short*) &mat[3][pmiq][i_rows*4+j_col])[1]);
}
for (int i_rows=N1*N2; i_rows<2*N1*N2; i_rows++) {
res_code=sqrt(1/(double)(4*CSI_RS_antenna_ports))*(phase_sign)*theta_n[nn]*v_lm[llc][mmc][i_rows-N1*N2];
if (creal(res_code)>0)
((short*) &mat[3][pmiq][i_rows*4+j_col])[0] = (short) ((creal(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[3][pmiq][i_rows*4+j_col])[0] = (short) ((creal(res_code)*32768)-0.5);//convert to Q15
if (cimag(res_code)>0)
((short*) &mat[3][pmiq][i_rows*4+j_col])[1] = (short) ((cimag(res_code)*32768)+0.5);//convert to Q15
else
((short*) &mat[3][pmiq][i_rows*4+j_col])[1] = (short) ((cimag(res_code)*32768)-0.5);//convert to Q15
LOG_D(PHY, "4 Layer Precoding Matrix[3][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq,i_rows,j_col, creal(res_code), cimag(res_code),((short*) &mat[3][pmiq][i_rows*4+j_col])[0],((short*) &mat[3][pmiq][i_rows*4+j_col])[1]);
}
}
}
}
}
}
}
}
}
}
}
return 0;
}
// A global var to reduce the changes size
ldpc_interface_t ldpc_interface = {0}, ldpc_interface_offload = {0};
......@@ -536,8 +134,6 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB)
if (gNB->ldpc_offload_flag)
load_LDPClib("_t2", &ldpc_interface_offload);
gNB->max_nb_pdsch = MAX_MOBILES_PER_GNB;
init_codebook_gNB(gNB);
init_delay_table(fp->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, fp->delay_table);
// PBCH DMRS gold sequences generation
......@@ -725,23 +321,15 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB)
void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
{
NR_DL_FRAME_PARMS* const fp = &gNB->frame_parms;
NR_DL_FRAME_PARMS* const fp = &gNB->frame_parms;
const int Ptx = gNB->gNB_config.carrier_config.num_tx_ant.value;
const int Prx = gNB->gNB_config.carrier_config.num_rx_ant.value;
const int max_ul_mimo_layers = 4; // taken from phy_init_nr_gNB()
const int n_buf = Prx * max_ul_mimo_layers;
PHY_MEASUREMENTS_gNB *meas=&gNB->measurements;
PHY_MEASUREMENTS_gNB *meas = &gNB->measurements;
free_and_zero(meas->n0_subband_power);
free_and_zero(meas->n0_subband_power_dB);
int max_dl_mimo_layers =(fp->nb_antennas_tx<NR_MAX_NB_LAYERS) ? fp->nb_antennas_tx : NR_MAX_NB_LAYERS;
if (fp->nb_antennas_tx>1) {
for (int nl = 0; nl < max_dl_mimo_layers; nl++) {
for(int size = 0; size < gNB->pmiq_size[nl]; size++)
free_and_zero(gNB->nr_mimo_precoding_matrix[nl][size]);
free_and_zero(gNB->nr_mimo_precoding_matrix[nl]);
}
free_and_zero(gNB->nr_mimo_precoding_matrix);
}
uint32_t ***pdcch_dmrs = gNB->nr_gold_pdcch_dmrs;
for (int slot = 0; slot < fp->slots_per_frame; slot++) {
......
......@@ -703,13 +703,17 @@ c16_t nr_layer_precoder_cm(int n_layers,
int n_symbols,
int symSz,
c16_t datatx_F_precoding[n_layers][n_symbols][symSz],
c16_t *prec_matrix,
int ap,
nfapi_nr_pm_pdu_t *pmi_pdu,
int symbol,
int offset)
{
c16_t precodatatx_F = {0};
for (int al = 0; al < n_layers; al++)
precodatatx_F = c16maddShift(datatx_F_precoding[al][symbol][offset], prec_matrix[al], precodatatx_F, 15);
for (int al = 0; al < n_layers; al++) {
nfapi_nr_pm_weights_t *w = &pmi_pdu->weights[al][ap];
c16_t prec_weight = {.r = w->precoder_weight_Re, .i = w->precoder_weight_Im};
precodatatx_F = c16maddShift(datatx_F_precoding[al][symbol][offset], prec_weight, precodatatx_F, 15);
}
return precodatatx_F;
}
......@@ -717,69 +721,77 @@ void nr_layer_precoder_simd(const int n_layers,
const int n_symbols,
const int symSz,
const c16_t txdataF_res_mapped[n_layers][n_symbols][symSz],
const c16_t prec_matrix[n_layers],
const int ant,
const nfapi_nr_pm_pdu_t *pmi_pdu,
const int symbol,
const int sc_offset,
const int re_cnt,
c16_t *txdataF_precoded)
{
uint32_t sc = sc_offset;
c16_t prec_weight = {0};
// For x86, use 256 SIMD for every 8 RE and 128 SIMD for last 4 RE
// For aarch64, use 128 SIMD for every 4 RE
// 256 SIMD: Do 8 RE in one iteration, 3 iterations for 2 RB
#ifdef __AVX2__
const uint32_t re_cnt_align8 = re_cnt & ~7;
for(; sc<sc_offset+(re_cnt_align8); sc+=sizeof(simde__m256i)/sizeof(*prec_matrix)){
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
simde__m256i y = simde_mm256_set1_epi16(0); // Y = W[0]*X[0] + W[1]*X[1] + ... + W[nrOfLayers-1]*X[nrOfLayers-1]
for(int nl=0; nl<n_layers; nl++){
const simde__m256i x = simde_mm256_loadu_epi32(&txdataF_res_mapped[nl][symbol][sc]);
// Rearrange precoding matrix weight to match complex multiplication and broadcast it to match SIMD size
const simde__m256i w_c = simde_mm256_set1_epi32(c16toI32(c16conj(prec_matrix[nl]))); // broadcast conjugate of w
const simde__m256i w_s = simde_mm256_set1_epi32(c16toI32(c16swap(prec_matrix[nl]))); // broadcast swapped real and img of w
// Multiplication and shift
const simde__m256i reals = simde_mm256_srai_epi32(simde_mm256_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15
const simde__m256i imags = simde_mm256_slli_epi32(simde_mm256_madd_epi16(x, w_s), 1); // (int32_t) .i = (x.r * w.i + x.i * w.r) << 1, since higher 16 bit of each 32 bit is taken by blend_epi16
// Re-arrange to match c16_t format
const simde__m256i produ = simde_mm256_blend_epi16(reals, imags, 0xAA);
// Accumulate the product
y = simde_mm256_adds_epi16(y, produ);
}
// Store the result to txdataF
simde_mm256_storeu_si256(&txdataF_precoded[sc], y);
#ifdef __AVX2__
const uint32_t re_cnt_align8 = re_cnt & ~7;
for(; sc < sc_offset + (re_cnt_align8); sc += sizeof(simde__m256i) / sizeof(prec_weight)) {
// Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8)
simde__m256i y = simde_mm256_set1_epi16(0); // Y = W[0]*X[0] + W[1]*X[1] + ... + W[nrOfLayers-1]*X[nrOfLayers-1]
for(int nl = 0; nl < n_layers; nl++) {
prec_weight.r = pmi_pdu->weights[nl][ant].precoder_weight_Re;
prec_weight.i = pmi_pdu->weights[nl][ant].precoder_weight_Im;
const simde__m256i x = simde_mm256_loadu_epi32(&txdataF_res_mapped[nl][symbol][sc]);
// Rearrange precoding matrix weight to match complex multiplication and broadcast it to match SIMD size
const simde__m256i w_c = simde_mm256_set1_epi32(c16toI32(c16conj(prec_weight))); // broadcast conjugate of w
const simde__m256i w_s = simde_mm256_set1_epi32(c16toI32(c16swap(prec_weight))); // broadcast swapped real and img of w
// Multiplication and shift
const simde__m256i reals = simde_mm256_srai_epi32(simde_mm256_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15
const simde__m256i imags = simde_mm256_slli_epi32(simde_mm256_madd_epi16(x, w_s), 1); // (int32_t) .i = (x.r * w.i + x.i * w.r) << 1, since higher 16 bit of each 32 bit is taken by blend_epi16
// Re-arrange to match c16_t format
const simde__m256i produ = simde_mm256_blend_epi16(reals, imags, 0xAA);
// Accumulate the product
y = simde_mm256_adds_epi16(y, produ);
}
#endif
// Store the result to txdataF
simde_mm256_storeu_si256(&txdataF_precoded[sc], y);
}
#endif
// 128 SIMD: Do 4 RE in one iteration, 3 iterations for 1 RB
const uint32_t re_cnt_align4 = re_cnt & ~3;
for(; sc<sc_offset+re_cnt_align4; sc+=sizeof(simde__m128i)/sizeof(*prec_matrix)){
for(; sc < sc_offset+re_cnt_align4; sc += sizeof(simde__m128i) / sizeof(prec_weight)) {
#ifdef DEBUG_DLSCH_PRECODING_PRINT_WITH_TRIVIAL // Get result with trivial solution, TODO: To be removed
c16_t y_triv[4];
for(int i=0; i<4; i++)
for(int i = 0; i < 4; i++)
y_triv[i] = nr_layer_precoder_cm(n_layers,
NR_SYMBOLS_PER_SLOT,
symSz,
txdataF_res_mapped,
prec_matrix,
symbol,
sc + i);
NR_SYMBOLS_PER_SLOT,
symSz,
txdataF_res_mapped,
ant,
pmi_pdu,
symbol,
sc + i);
memcpy(&txdataF_precoded[sc], y_triv, sizeof(y_triv));
#endif
// Matrix multiplication for 4 elements of the result (sizeof(simde__m128i) / sizeof(c16_t) = 4)
simde__m128i y = simde_mm_set1_epi16(0); // Y = W[0]*X[0] + W[1]*X[1] + ... + W[nrOfLayers-1]*X[nrOfLayers-1]
for(int nl=0; nl<n_layers; nl++){
for(int nl = 0; nl < n_layers; nl++) {
prec_weight.r = pmi_pdu->weights[nl][ant].precoder_weight_Re;
prec_weight.i = pmi_pdu->weights[nl][ant].precoder_weight_Im;
const simde__m128i x = simde_mm_loadu_epi32(&txdataF_res_mapped[nl][symbol][sc]);
// Rearrange precoding matrix weight to match complex multiplication and broadcast it to match SIMD size
const simde__m128i w_c = simde_mm_set1_epi32(c16toI32(c16conj(prec_matrix[nl]))); // broadcast conjugate of w
const simde__m128i w_s = simde_mm_set1_epi32(c16toI32(c16swap(prec_matrix[nl]))); // broadcast swapped real and img of w
const simde__m128i w_c = simde_mm_set1_epi32(c16toI32(c16conj(prec_weight))); // broadcast conjugate of w
const simde__m128i w_s = simde_mm_set1_epi32(c16toI32(c16swap(prec_weight))); // broadcast swapped real and img of w
// Multiplication and shift
const simde__m128i reals = simde_mm_srai_epi32(simde_mm_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15
......
......@@ -138,11 +138,13 @@ void apply_nr_rotation_RX(NR_DL_FRAME_PARMS *frame_parms,
@param[in] n_layers, number of DLSCH layers
*/
int nr_layer_precoder(int16_t **datatx_F_precoding, const char *prec_matrix, uint8_t n_layers, int32_t re_offset);
c16_t nr_layer_precoder_cm(int n_layers,
int n_symbols,
int symSz,
c16_t datatx_F_precoding[n_layers][n_symbols][symSz],
c16_t *prec_matrix,
int ap,
nfapi_nr_pm_pdu_t *pmi_pdu,
int symbol,
int offset);
......@@ -156,7 +158,8 @@ void nr_layer_precoder_simd(const int n_layers,
const int n_symbols,
const int symSz,
const c16_t txdataF_res_mapped[n_layers][n_symbols][symSz],
const c16_t prec_matrix[n_layers],
const int ant,
const nfapi_nr_pm_pdu_t *pmi_pdu,
const int symbol,
const int sc_offset,
const int re_cnt,
......
......@@ -535,58 +535,52 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
}
}
else { // non-unitary Precoding
if(frame_parms->nb_antennas_tx == 1){ // no precoding matrix defined
memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
&txdataF_precoding[ant][l_symbol][subCarrier],
re_cnt * sizeof(**txdataF));
AssertFatal(frame_parms->nb_antennas_tx > 1, "No precoding can be done with a single antenna port\n");
//get the precoding matrix weights:
nfapi_nr_pm_pdu_t *pmi_pdu = &gNB->gNB_config.pmi_list.pmi_pdu[pmi - 1]; // pmi 0 is identity matrix
AssertFatal(pmi == pmi_pdu->pm_idx, "PMI %d doesn't match to the one in precoding matrix %d\n",
pmi, pmi_pdu->pm_idx);
AssertFatal(ant < pmi_pdu->num_ant_ports, "Antenna port index %d exceeds precoding matrix AP size %d\n",
ant, pmi_pdu->num_ant_ports);
AssertFatal(rel15->nrOfLayers == pmi_pdu->numLayers, "Number of layers %d doesn't match to the one in precoding matrix %d\n",
rel15->nrOfLayers, pmi_pdu->numLayers);
if((subCarrier + re_cnt) < frame_parms->ofdm_symbol_size){ // within ofdm_symbol_size, use SIMDe
nr_layer_precoder_simd(rel15->nrOfLayers,
NR_SYMBOLS_PER_SLOT,
frame_parms->ofdm_symbol_size,
txdataF_precoding,
ant,
pmi_pdu,
l_symbol,
subCarrier,
re_cnt,
&txdataF[ant][txdataF_offset_per_symbol]);
subCarrier += re_cnt;
if (subCarrier >= frame_parms->ofdm_symbol_size) {
subCarrier -= frame_parms->ofdm_symbol_size;
}
}
else { // precoding with more than 1 tx
//get the precoding matrix weights:
c16_t **mat = (c16_t**)gNB->nr_mimo_precoding_matrix[rel15->nrOfLayers - 1];
//i_row =0,...,dl_antenna_port
//j_col =0,...,nrOfLayers
//mat[pmi][i_rows*2+j_col]
c16_t *W_prec = &mat[pmi][ant * rel15->nrOfLayers];
if((subCarrier + re_cnt) < frame_parms->ofdm_symbol_size){ // within ofdm_symbol_size, use SIMDe
nr_layer_precoder_simd(rel15->nrOfLayers,
NR_SYMBOLS_PER_SLOT,
frame_parms->ofdm_symbol_size,
txdataF_precoding,
W_prec,
l_symbol,
subCarrier,
re_cnt,
&txdataF[ant][txdataF_offset_per_symbol]);
subCarrier += re_cnt;
}
else{ // crossing ofdm_symbol_size, use simple arithmetic operations
for (int i = 0; i < re_cnt; i++) {
txdataF[ant][txdataF_offset_per_symbol + subCarrier] =
nr_layer_precoder_cm(rel15->nrOfLayers,
NR_SYMBOLS_PER_SLOT,
frame_parms->ofdm_symbol_size,
txdataF_precoding,
W_prec,
l_symbol,
subCarrier);
else{ // crossing ofdm_symbol_size, use simple arithmetic operations
for (int i = 0; i < re_cnt; i++) {
txdataF[ant][txdataF_offset_per_symbol + subCarrier] =
nr_layer_precoder_cm(rel15->nrOfLayers,
NR_SYMBOLS_PER_SLOT,
frame_parms->ofdm_symbol_size,
txdataF_precoding,
ant,
pmi_pdu,
l_symbol,
subCarrier);
#ifdef DEBUG_DLSCH_MAPPING
printf("antenna %d\t l %d \t subCarrier %d \t txdataF: %d %d\n",
ant,
symbol,
subCarrier,
txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].r,
txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].i);
printf("antenna %d\t l %d \t subCarrier %d \t txdataF: %d %d\n",
ant,
symbol,
subCarrier,
txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].r,
txdataF[ant][l_symbol * frame_parms->ofdm_symbol_size + subCarrier + txdataF_offset].i);
#endif
if (++subCarrier >= frame_parms->ofdm_symbol_size) {
subCarrier -= frame_parms->ofdm_symbol_size;
}
if (++subCarrier >= frame_parms->ofdm_symbol_size) {
subCarrier -= frame_parms->ofdm_symbol_size;
}
} // else{ // crossing ofdm_symbol_size, use simple arithmetic operations
} // else { // precoding with more than 1 tx
}
} // else{ // crossing ofdm_symbol_size, use simple arithmetic operations
} // else { // non-unitary Precoding
rb += rb_step;
......
......@@ -619,13 +619,6 @@ typedef struct PHY_VARS_gNB_s {
/// PDSCH DMRS sequence
uint32_t ****nr_gold_pdsch_dmrs;
/// PDSCH codebook I precoding LUTs
/// first dimension: Rank number [0,...,noOfLayers-1[
/// second dimension: PMI [0,...,CodeSize-1[
/// third dimension: [i_rows*noOfLayers+j_col], i_rows=0,...pdsch_AntennaPorts-1 and j_col=0,...,noOfLayers-1
int32_t ***nr_mimo_precoding_matrix;
int pmiq_size[NR_MAX_NB_LAYERS];
/// PUSCH DMRS
uint32_t ****nr_gold_pusch_dmrs;
......
......@@ -79,7 +79,6 @@
#define NR_MAX_PDCCH_AGG_LEVEL 16 // 3GPP TS 38.211 V15.8 Section 7.3.2 Table 7.3.2.1-1: Supported PDCCH aggregation levels
#define NR_MAX_NB_LAYERS 4 // 8
#define NR_MAX_NB_PORTS 32
#define NR_MAX_PDSCH_TBS 3824
......
......@@ -223,35 +223,21 @@ nrUE_params_t *get_nrUE_params(void) {
}
void validate_input_pmi(nr_pdsch_AntennaPorts_t pdsch_AntennaPorts, int nrOfLayers, int pmi)
void validate_input_pmi(nfapi_nr_config_request_scf_t *gNB_config,
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts,
int nrOfLayers,
int pmi)
{
if (pmi == 0)
return;
nfapi_nr_pm_pdu_t *pmi_pdu = &gNB_config->pmi_list.pmi_pdu[pmi - 1]; // pmi 0 is identity matrix
AssertFatal(pmi == pmi_pdu->pm_idx, "PMI %d doesn't match to the one in precoding matrix %d\n", pmi, pmi_pdu->pm_idx);
AssertFatal(nrOfLayers == pmi_pdu->numLayers, "Number of layers %d doesn't match to the one in precoding matrix %d for PMI %d\n",
nrOfLayers, pmi_pdu->numLayers, pmi);
int num_antenna_ports = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP;
int N1 = pdsch_AntennaPorts.N1;
int N2 = pdsch_AntennaPorts.N2;
int O1 = N1 > 1 ? 4 : 1;
int O2 = N2 > 1 ? 4 : 1;
int K1, K2;
if (num_antenna_ports > 2)
get_K1_K2(N1, N2, &K1, &K2);
else {
K1 = 1; K2 = 1;
}
int num_pmi = 1; // pmi = 0 is the identity matrix
switch (nrOfLayers) {
case 1 :
num_pmi += N1 * O1 * N2 * O2 * 4;
AssertFatal(pmi < num_pmi, "Input PMI index %d exceeds the limit of configured matrices %d for %d layers\n", pmi, num_pmi, nrOfLayers);
return;
case 2 :
num_pmi += N1 * O1 * N2 * O2 * K1 * K2 * 2;
AssertFatal(pmi < num_pmi, "Input PMI index %d exceeds the limit of conigured matrices %d for %d layers\n", pmi, num_pmi, nrOfLayers);
break;
default :
AssertFatal(false, "Precoding with more than 2 nrOfLayers not yet supported\n");
}
AssertFatal(num_antenna_ports == pmi_pdu->num_ant_ports, "Configured antenna ports %d does not match precoding matrix AP size %d for PMI %d\n",
num_antenna_ports, pmi_pdu->num_ant_ports, pmi);
}
......@@ -709,7 +695,7 @@ int main(int argc, char **argv)
gNB->ap_N2 = pdsch_AntennaPorts.N2;
gNB->ap_XP = pdsch_AntennaPorts.XP;
validate_input_pmi(pdsch_AntennaPorts, g_nrOfLayers, g_pmi);
validate_input_pmi(&gNB_mac->config[0], pdsch_AntennaPorts, g_nrOfLayers, g_pmi);
NR_UE_NR_Capability_t* UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t));
prepare_sim_uecap(UE_Capability_nr,scc,mu,
......
......@@ -50,11 +50,319 @@
#include "../../../../nfapi/oai_integration/vendor_ext.h"
/* Softmodem params */
#include "executables/softmodem-common.h"
#include <complex.h>
extern RAN_CONTEXT_t RC;
//extern int l2_init_gNB(void);
extern uint8_t nfapi_mode;
c16_t convert_precoder_weight(double complex c_in)
{
double cr = creal(c_in) * 32768 + 0.5;
if (cr < 0)
cr -= 1;
double ci = cimag(c_in) * 32768 + 0.5;
if (ci < 0)
ci -= 1;
return (c16_t) {.r = (short)cr, .i = (short)ci};
}
nfapi_nr_pm_list_t init_DL_MIMO_codebook(gNB_MAC_INST *gNB, nr_pdsch_AntennaPorts_t antenna_ports)
{
int num_antenna_ports = antenna_ports.N1 * antenna_ports.N2 * antenna_ports.XP;
if (num_antenna_ports < 2)
return (nfapi_nr_pm_list_t) {0};
//NR Codebook Generation for codebook type1 SinglePanel
int N1 = antenna_ports.N1;
int N2 = antenna_ports.N2;
//Uniform Planner Array: UPA
// X X X X ... X
// X X X X ... X
// N2 . . . . ... .
// X X X X ... X
// |<-----N1---->|
//Get the uniform planar array parameters
// To be confirmed
int O2 = N2 > 1 ? 4 : 1; //Vertical beam oversampling (1 or 4)
int O1 = num_antenna_ports > 2 ? 4 : 1; //Horizontal beam oversampling (1 or 4)
int K1, K2;
get_K1_K2(N1, N2, &K1, &K2);
int max_mimo_layers = (num_antenna_ports < NR_MAX_NB_LAYERS) ? num_antenna_ports : NR_MAX_NB_LAYERS;
AssertFatal(max_mimo_layers <= 4, "Max number of layers supported is 4\n");
gNB->precoding_matrix_size[0] = N1 * O1 * N2 * O2 * 4;
nfapi_nr_pm_list_t mat = {.num_pm_idx = gNB->precoding_matrix_size[0]};
for (int i = 1; i < max_mimo_layers; i++) {
gNB->precoding_matrix_size[i] = 2 * N1 * O1 * N2 * O2 * K1 * K2;
mat.num_pm_idx += gNB->precoding_matrix_size[i];
}
nfapi_nr_pm_pdu_t *pmi_pdu = malloc16(mat.num_pm_idx * sizeof(*pmi_pdu));
AssertFatal(pmi_pdu != NULL, "out of memory\n");
mat.pmi_pdu = pmi_pdu;
// Generation of codebook Type1 with codebookMode 1 (num_antenna_ports < 16)
if (num_antenna_ports < 16) {
//Generate DFT vertical beams
//ll: index of a vertical beams vector (represented by i1_1 in TS 38.214)
const int max_l = N1 * O1 + (K1 - 1) * O1;
double complex v[max_l][N1];
for (int ll = 0; ll < max_l; ll++) { //i1_1
for (int nn = 0; nn < N1; nn++) {
v[ll][nn] = cexp(I * (2 * M_PI * nn * ll) / (N1 * O1));
LOG_D(PHY,"v[%d][%d] = %f +j %f\n", ll, nn, creal(v[ll][nn]), cimag(v[ll][nn]));
}
}
//Generate DFT Horizontal beams
//mm: index of a Horizontal beams vector (represented by i1_2 in TS 38.214)
const int max_m = N2 * O2 + (K2 - 1) * O2;
double complex u[max_m][N2];
for (int mm = 0; mm < max_m; mm++) { //i1_2
for (int nn = 0; nn < N2; nn++) {
u[mm][nn] = cexp(I * (2 * M_PI * nn * mm) / (N2 * O2));
LOG_D(PHY,"u[%d][%d] = %f +j %f\n", mm, nn, creal(u[mm][nn]), cimag(u[mm][nn]));
}
}
//Generate co-phasing angles
//i_2: index of a co-phasing vector
//i1_1, i1_2, and i_2 are reported from UEs
double complex theta_n[4];
for (int nn = 0; nn < 4; nn++) {
theta_n[nn] = cexp(I * M_PI * nn / 2);
LOG_D(PHY,"theta_n[%d] = %f +j %f\n", nn, creal(theta_n[nn]), cimag(theta_n[nn]));
}
//Kronecker product v_lm
double complex v_lm[max_l][max_m][N2 * N1];
//v_ll_mm_codebook denotes the elements of a precoding matrix W_i1,1_i_1,2
for(int ll = 0; ll < max_l; ll++) { //i_1_1
for (int mm = 0; mm < max_m; mm++) { //i_1_2
for (int nn1 = 0; nn1 < N1; nn1++) {
for (int nn2 = 0; nn2 < N2; nn2++) {
v_lm[ll][mm][nn1 * N2 + nn2] = v[ll][nn1] * u[mm][nn2];
LOG_D(PHY,"v_lm[%d][%d][%d] = %f +j %f\n",ll, mm, nn1 * N2 + nn2, creal(v_lm[ll][mm][nn1*N2+nn2]), cimag(v_lm[ll][mm][nn1*N2+nn2]));
}
}
}
}
double complex res_code;
//Table 5.2.2.2.1-5:
int pmiq = 0;
//Codebook for 1-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
for(int ll = 0; ll < N1 * O1; ll++) { //i_1_1
for (int mm = 0; mm < N2 * O2; mm++) { //i_1_2
for (int nn = 0; nn < 4; nn++) {
pmiq = ll * N2 * O2 * 4 + mm * 4 + nn;
pmi_pdu[pmiq].pm_idx = pmiq + 1; // index 0 is the identity matrix
pmi_pdu[pmiq].numLayers = 1;
pmi_pdu[pmiq].num_ant_ports = num_antenna_ports;
LOG_D(PHY, "layer 1 Codebook pmiq = %d\n", pmiq);
for (int len = 0; len < N1 * N2; len++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[0][len];
res_code = sqrt( 1 /(double)num_antenna_ports) * v_lm[ll][mm][len];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "1 Layer Precoding Matrix[0][pmi %d][antPort %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, len, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
for(int len = N1 * N2; len < 2 * N1 * N2; len++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[0][len];
res_code = sqrt(1 / (double)num_antenna_ports) * theta_n[nn] * v_lm[ll][mm][len-N1*N2];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "1 Layer Precoding Matrix[0][pmi %d][antPort %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, len, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
}
}
}
int llc = 0;
int mmc = 0;
double complex phase_sign = 0;
//Table 5.2.2.2.1-6:
//Codebook for 2-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
//Compute the code book size for generating 2 layers out of Tx antenna ports
//pmi=1,...,pmi_size, we construct
for(int ll = 0; ll < N1 * O1; ll++) { //i_1_1
for (int mm = 0; mm < N2 * O2; mm++) { // i_1_2
for(int k1 = 0; k1 < K1; k1++) {
for (int k2 = 0; k2 < K2; k2++) {
for (int nn = 0; nn < 2; nn++) { // i_2
pmiq ++;
pmi_pdu[pmiq].pm_idx = pmiq + 1; // index 0 is the identity matrix
pmi_pdu[pmiq].numLayers = 2;
pmi_pdu[pmiq].num_ant_ports = num_antenna_ports;
LOG_D(PHY, "layer 2 Codebook pmiq = %d\n", pmiq);
for(int j_col = 0; j_col < 2; j_col++) {
if (j_col == 0) {
llc = ll;
mmc = mm;
phase_sign = 1;
}
if (j_col == 1) {
llc = ll + k1 * O1;
mmc = mm + k2 * O2;
phase_sign = -1;
}
for (int i_rows = 0; i_rows < N1 * N2; i_rows++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[j_col][i_rows];
res_code = sqrt(1 / (double)(2 * num_antenna_ports)) * v_lm[llc][mmc][i_rows];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "2 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, i_rows, j_col, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
for (int i_rows = N1 * N2; i_rows < 2 * N1 * N2; i_rows++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[j_col][i_rows];
res_code = sqrt(1 / (double)(2 * num_antenna_ports)) * (phase_sign) * theta_n[nn] * v_lm[llc][mmc][i_rows - N1 * N2];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "2 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, i_rows, j_col, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
}
}
}
}
}
}
if(max_mimo_layers < 3)
return mat;
//Table 5.2.2.2.1-7:
//Codebook for 3-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
//pmi=1,...,pmi_size are computed as follows
for(int ll = 0; ll < N1 * O1; ll++) { //i_1_1
for (int mm = 0; mm < N2 * O2; mm++) { // i_1_2
for(int k1 = 0; k1 < K1; k1++) {
for (int k2 = 0; k2 < K2; k2++) {
for (int nn = 0; nn < 2; nn++) { // i_2
pmiq ++;
pmi_pdu[pmiq].pm_idx = pmiq + 1; // index 0 is the identity matrix
pmi_pdu[pmiq].numLayers = 3;
pmi_pdu[pmiq].num_ant_ports = num_antenna_ports;
LOG_D(PHY, "layer 3 Codebook pmiq = %d\n",pmiq);
for(int j_col = 0; j_col < 3; j_col++) {
if (j_col == 0) {
llc = ll;
mmc = mm;
phase_sign = 1;
}
if (j_col==1) {
llc = ll + k1 * O1;
mmc = mm + k2 * O2;
phase_sign = 1;
}
if (j_col==2) {
llc = ll;
mmc = mm;
phase_sign = -1;
}
for (int i_rows = 0; i_rows < N1 * N2; i_rows++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[j_col][i_rows];
res_code = sqrt(1 / (double)(3 * num_antenna_ports)) * v_lm[llc][mmc][i_rows];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "3 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, i_rows, j_col, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
for (int i_rows = N1 * N2; i_rows < 2 * N1 * N2; i_rows++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[j_col][i_rows];
res_code=sqrt(1 / (double)(3 * num_antenna_ports)) * (phase_sign) * theta_n[nn] * v_lm[llc][mmc][i_rows - N1 * N2];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "3 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, i_rows, j_col, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
}
}
}
}
}
}
if(max_mimo_layers < 4)
return mat;
//Table 5.2.2.2.1-8:
//Codebook for 4-layer CSI reporting using antenna ports 3000 to 2999+PCSI-RS
for(int ll = 0; ll < N1 * O1; ll++) { //i_1_1
for (int mm = 0; mm < N2 * O2; mm++) { // i_1_2
for(int k1 = 0; k1 < K1; k1++) {
for (int k2 = 0; k2 < K2; k2++) {
for (int nn = 0; nn < 2; nn++) { // i_2
pmiq ++;
pmi_pdu[pmiq].pm_idx = pmiq + 1; // index 0 is the identity matrix
pmi_pdu[pmiq].numLayers = 4;
pmi_pdu[pmiq].num_ant_ports = num_antenna_ports;
LOG_D(PHY, "layer 4 pmiq = %d\n", pmiq);
for(int j_col = 0; j_col < 4; j_col++) {
if (j_col == 0) {
llc = ll;
mmc = mm;
phase_sign = 1;
}
if (j_col == 1) {
llc = ll + k1 * O1;
mmc = mm + k2 * O2;
phase_sign = 1;
}
if (j_col == 2) {
llc = ll;
mmc = mm;
phase_sign = -1;
}
if (j_col == 3) {
llc = ll + k1 * O1;
mmc = mm + k2 * O2;
phase_sign = -1;
}
for (int i_rows = 0; i_rows < N1 * N2; i_rows++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[j_col][i_rows];
res_code=sqrt(1 / (double)(4 * num_antenna_ports)) * v_lm[llc][mmc][i_rows];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "4 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, i_rows, j_col, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
for (int i_rows = N1 * N2; i_rows < 2 * N1 * N2; i_rows++) {
nfapi_nr_pm_weights_t *weights = &pmi_pdu[pmiq].weights[j_col][i_rows];
res_code=sqrt(1 / (double)(4 * num_antenna_ports)) * (phase_sign) * theta_n[nn] * v_lm[llc][mmc][i_rows - N1 * N2];
c16_t precoder_weight = convert_precoder_weight(res_code);
weights->precoder_weight_Re = precoder_weight.r;
weights->precoder_weight_Im = precoder_weight.i;
LOG_D(PHY, "4 Layer Precoding Matrix[1][pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n",
pmiq, i_rows, j_col, creal(res_code), cimag(res_code), weights->precoder_weight_Re, weights->precoder_weight_Im);
}
}
}
}
}
}
}
return mat;
}
else
AssertFatal(false, "Max number of antenna ports supported is currently 16\n");
}
static void process_rlcBearerConfig(struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list,
struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_bearer2release_list,
NR_UE_sched_ctrl_t *sched_ctrl)
......@@ -122,30 +430,30 @@ void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_info_t *UE)
process_rlcBearerConfig(CellGroup->rlc_BearerToAddModList, CellGroup->rlc_BearerToReleaseList, &UE->UE_sched_ctrl);
}
static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc)
static void config_common(gNB_MAC_INST *nrmac, nr_pdsch_AntennaPorts_t pdsch_AntennaPorts, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc)
{
nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0];
nrmac->common_channels[0].ServingCellConfigCommon = scc;
// Carrier configuration
struct NR_FrequencyInfoDL *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
int bw_index = get_supported_band_index(frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
*frequencyInfoDL->frequencyBandList.list.array[0],
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.dl_bandwidth.value =
nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0];
nrmac->common_channels[0].ServingCellConfigCommon = scc;
// Carrier configuration
struct NR_FrequencyInfoDL *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
int bw_index = get_supported_band_index(frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
*frequencyInfoDL->frequencyBandList.list.array[0],
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.dl_bandwidth.value =
get_supported_bw_mhz(*frequencyInfoDL->frequencyBandList.list.array[0] > 256 ? FR2 : FR1, bw_index);
cfg->carrier_config.dl_bandwidth.tl.tag = NFAPI_NR_CONFIG_DL_BANDWIDTH_TAG; // temporary
cfg->num_tlv++;
LOG_I(NR_MAC, "%s() dl_BandwidthP:%d\n", __FUNCTION__, cfg->carrier_config.dl_bandwidth.value);
cfg->carrier_config.dl_bandwidth.tl.tag = NFAPI_NR_CONFIG_DL_BANDWIDTH_TAG; // temporary
cfg->num_tlv++;
LOG_I(NR_MAC, "DL_Bandwidth:%d\n", cfg->carrier_config.dl_bandwidth.value);
cfg->carrier_config.dl_frequency.value = from_nrarfcn(*frequencyInfoDL->frequencyBandList.list.array[0],
*scc->ssbSubcarrierSpacing,
frequencyInfoDL->absoluteFrequencyPointA)
cfg->carrier_config.dl_frequency.value = from_nrarfcn(*frequencyInfoDL->frequencyBandList.list.array[0],
*scc->ssbSubcarrierSpacing,
frequencyInfoDL->absoluteFrequencyPointA)
/ 1000; // freq in kHz
cfg->carrier_config.dl_frequency.tl.tag = NFAPI_NR_CONFIG_DL_FREQUENCY_TAG;
cfg->num_tlv++;
cfg->carrier_config.dl_frequency.tl.tag = NFAPI_NR_CONFIG_DL_FREQUENCY_TAG;
cfg->num_tlv++;
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 5; i++) {
if (i == frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) {
cfg->carrier_config.dl_grid_size[i].value = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
cfg->carrier_config.dl_k0[i].value = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier;
......@@ -157,31 +465,31 @@ static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch
cfg->carrier_config.dl_grid_size[i].value = 0;
cfg->carrier_config.dl_k0[i].value = 0;
}
}
struct NR_FrequencyInfoUL *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL;
bw_index = get_supported_band_index(frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
*frequencyInfoUL->frequencyBandList->list.array[0],
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.uplink_bandwidth.value =
}
struct NR_FrequencyInfoUL *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL;
bw_index = get_supported_band_index(frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
*frequencyInfoUL->frequencyBandList->list.array[0],
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.uplink_bandwidth.value =
get_supported_bw_mhz(*frequencyInfoUL->frequencyBandList->list.array[0] > 256 ? FR2 : FR1, bw_index);
cfg->carrier_config.uplink_bandwidth.tl.tag = NFAPI_NR_CONFIG_UPLINK_BANDWIDTH_TAG; // temporary
cfg->num_tlv++;
LOG_I(NR_MAC, "%s() dl_BandwidthP:%d\n", __FUNCTION__, cfg->carrier_config.uplink_bandwidth.value);
cfg->carrier_config.uplink_bandwidth.tl.tag = NFAPI_NR_CONFIG_UPLINK_BANDWIDTH_TAG; // temporary
cfg->num_tlv++;
LOG_I(NR_MAC, "DL_Bandwidth:%d\n", cfg->carrier_config.uplink_bandwidth.value);
int UL_pointA;
if (frequencyInfoUL->absoluteFrequencyPointA == NULL)
int UL_pointA;
if (frequencyInfoUL->absoluteFrequencyPointA == NULL)
UL_pointA = frequencyInfoDL->absoluteFrequencyPointA;
else
else
UL_pointA = *frequencyInfoUL->absoluteFrequencyPointA;
cfg->carrier_config.uplink_frequency.value = from_nrarfcn(*frequencyInfoUL->frequencyBandList->list.array[0],
*scc->ssbSubcarrierSpacing,
UL_pointA)
/ 1000; // freq in kHz
cfg->carrier_config.uplink_frequency.tl.tag = NFAPI_NR_CONFIG_UPLINK_FREQUENCY_TAG;
cfg->num_tlv++;
cfg->carrier_config.uplink_frequency.value = from_nrarfcn(*frequencyInfoUL->frequencyBandList->list.array[0],
*scc->ssbSubcarrierSpacing,
UL_pointA)
/ 1000; // freq in kHz
cfg->carrier_config.uplink_frequency.tl.tag = NFAPI_NR_CONFIG_UPLINK_FREQUENCY_TAG;
cfg->num_tlv++;
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 5; i++) {
if (i == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) {
cfg->carrier_config.ul_grid_size[i].value = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
cfg->carrier_config.ul_k0[i].value = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier;
......@@ -193,61 +501,61 @@ static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch
cfg->carrier_config.ul_grid_size[i].value = 0;
cfg->carrier_config.ul_k0[i].value = 0;
}
}
}
uint32_t band = *frequencyInfoDL->frequencyBandList.list.array[0];
frequency_range_t frequency_range = band < 100 ? FR1 : FR2;
uint32_t band = *frequencyInfoDL->frequencyBandList.list.array[0];
frequency_range_t frequency_range = band < 100 ? FR1 : FR2;
frame_type_t frame_type = get_frame_type(*frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
nrmac->common_channels[0].frame_type = frame_type;
frame_type_t frame_type = get_frame_type(*frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
nrmac->common_channels[0].frame_type = frame_type;
// Cell configuration
cfg->cell_config.phy_cell_id.value = *scc->physCellId;
cfg->cell_config.phy_cell_id.tl.tag = NFAPI_NR_CONFIG_PHY_CELL_ID_TAG;
cfg->num_tlv++;
// Cell configuration
cfg->cell_config.phy_cell_id.value = *scc->physCellId;
cfg->cell_config.phy_cell_id.tl.tag = NFAPI_NR_CONFIG_PHY_CELL_ID_TAG;
cfg->num_tlv++;
cfg->cell_config.frame_duplex_type.value = frame_type;
cfg->cell_config.frame_duplex_type.tl.tag = NFAPI_NR_CONFIG_FRAME_DUPLEX_TYPE_TAG;
cfg->num_tlv++;
cfg->cell_config.frame_duplex_type.value = frame_type;
cfg->cell_config.frame_duplex_type.tl.tag = NFAPI_NR_CONFIG_FRAME_DUPLEX_TYPE_TAG;
cfg->num_tlv++;
// SSB configuration
cfg->ssb_config.ss_pbch_power.value = scc->ss_PBCH_BlockPower;
cfg->ssb_config.ss_pbch_power.tl.tag = NFAPI_NR_CONFIG_SS_PBCH_POWER_TAG;
cfg->num_tlv++;
// SSB configuration
cfg->ssb_config.ss_pbch_power.value = scc->ss_PBCH_BlockPower;
cfg->ssb_config.ss_pbch_power.tl.tag = NFAPI_NR_CONFIG_SS_PBCH_POWER_TAG;
cfg->num_tlv++;
cfg->ssb_config.bch_payload.value = 1;
cfg->ssb_config.bch_payload.tl.tag = NFAPI_NR_CONFIG_BCH_PAYLOAD_TAG;
cfg->num_tlv++;
cfg->ssb_config.bch_payload.value = 1;
cfg->ssb_config.bch_payload.tl.tag = NFAPI_NR_CONFIG_BCH_PAYLOAD_TAG;
cfg->num_tlv++;
cfg->ssb_config.scs_common.value = *scc->ssbSubcarrierSpacing;
cfg->ssb_config.scs_common.tl.tag = NFAPI_NR_CONFIG_SCS_COMMON_TAG;
cfg->num_tlv++;
cfg->ssb_config.scs_common.value = *scc->ssbSubcarrierSpacing;
cfg->ssb_config.scs_common.tl.tag = NFAPI_NR_CONFIG_SCS_COMMON_TAG;
cfg->num_tlv++;
// PRACH configuration
// PRACH configuration
uint8_t nb_preambles = 64;
NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
if (rach_ConfigCommon->totalNumberOfRA_Preambles != NULL)
uint8_t nb_preambles = 64;
NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
if (rach_ConfigCommon->totalNumberOfRA_Preambles != NULL)
nb_preambles = *rach_ConfigCommon->totalNumberOfRA_Preambles;
cfg->prach_config.prach_sequence_length.value = rach_ConfigCommon->prach_RootSequenceIndex.present - 1;
cfg->prach_config.prach_sequence_length.tl.tag = NFAPI_NR_CONFIG_PRACH_SEQUENCE_LENGTH_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_sequence_length.value = rach_ConfigCommon->prach_RootSequenceIndex.present - 1;
cfg->prach_config.prach_sequence_length.tl.tag = NFAPI_NR_CONFIG_PRACH_SEQUENCE_LENGTH_TAG;
cfg->num_tlv++;
if (rach_ConfigCommon->msg1_SubcarrierSpacing)
if (rach_ConfigCommon->msg1_SubcarrierSpacing)
cfg->prach_config.prach_sub_c_spacing.value = *rach_ConfigCommon->msg1_SubcarrierSpacing;
else
else
cfg->prach_config.prach_sub_c_spacing.value = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
cfg->prach_config.prach_sub_c_spacing.tl.tag = NFAPI_NR_CONFIG_PRACH_SUB_C_SPACING_TAG;
cfg->num_tlv++;
cfg->prach_config.restricted_set_config.value = rach_ConfigCommon->restrictedSetConfig;
cfg->prach_config.restricted_set_config.tl.tag = NFAPI_NR_CONFIG_RESTRICTED_SET_CONFIG_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
switch (rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM) {
cfg->prach_config.prach_sub_c_spacing.tl.tag = NFAPI_NR_CONFIG_PRACH_SUB_C_SPACING_TAG;
cfg->num_tlv++;
cfg->prach_config.restricted_set_config.value = rach_ConfigCommon->restrictedSetConfig;
cfg->prach_config.restricted_set_config.tl.tag = NFAPI_NR_CONFIG_RESTRICTED_SET_CONFIG_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
switch (rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM) {
case 0:
cfg->prach_config.num_prach_fd_occasions.value = 1;
break;
......@@ -262,17 +570,17 @@ static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch
break;
default:
AssertFatal(1 == 0, "msg1 FDM identifier %ld undefined (0,1,2,3) \n", rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM);
}
cfg->prach_config.num_prach_fd_occasions.tl.tag = NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG;
cfg->num_tlv++;
}
cfg->prach_config.num_prach_fd_occasions.tl.tag = NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
cfg->prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *)malloc(
cfg->prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *)malloc(
cfg->prach_config.num_prach_fd_occasions.value * sizeof(nfapi_nr_num_prach_fd_occasions_t));
for (int i = 0; i < cfg->prach_config.num_prach_fd_occasions.value; i++) {
for (int i = 0; i < cfg->prach_config.num_prach_fd_occasions.value; i++) {
nfapi_nr_num_prach_fd_occasions_t *prach_fd_occasion = &cfg->prach_config.num_prach_fd_occasions_list[i];
// prach_fd_occasion->num_prach_fd_occasions = i;
if (cfg->prach_config.prach_sequence_length.value)
......@@ -311,44 +619,45 @@ static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch
prach_fd_occasion->num_unused_root_sequences.tl.tag = NFAPI_NR_CONFIG_NUM_UNUSED_ROOT_SEQUENCES_TAG;
prach_fd_occasion->num_unused_root_sequences.value = 0;
cfg->num_tlv++;
}
}
cfg->prach_config.ssb_per_rach.value = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present - 1;
cfg->prach_config.ssb_per_rach.tl.tag = NFAPI_NR_CONFIG_SSB_PER_RACH_TAG;
cfg->num_tlv++;
cfg->prach_config.ssb_per_rach.value = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present - 1;
cfg->prach_config.ssb_per_rach.tl.tag = NFAPI_NR_CONFIG_SSB_PER_RACH_TAG;
cfg->num_tlv++;
// SSB Table Configuration
// SSB Table Configuration
cfg->ssb_table.ssb_offset_point_a.value =
cfg->ssb_table.ssb_offset_point_a.value =
get_ssb_offset_to_pointA(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB,
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
*scc->ssbSubcarrierSpacing,
frequency_range);
cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG;
cfg->num_tlv++;
cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell;
cfg->ssb_table.ssb_period.tl.tag = NFAPI_NR_CONFIG_SSB_PERIOD_TAG;
cfg->num_tlv++;
cfg->ssb_table.ssb_subcarrier_offset.value =
cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG;
cfg->num_tlv++;
cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell;
cfg->ssb_table.ssb_period.tl.tag = NFAPI_NR_CONFIG_SSB_PERIOD_TAG;
cfg->num_tlv++;
cfg->ssb_table.ssb_subcarrier_offset.value =
get_ssb_subcarrier_offset(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB,
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA);
AssertFatal(cfg->ssb_table.ssb_subcarrier_offset.value < 16,
"cannot handle ssb_subcarrier_offset %d resulting from Point A %ld SSB %ld: please increase dl_absoluteFrequencyPointA "
"in the config by 16\n",
cfg->ssb_table.ssb_subcarrier_offset.value,
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB);
cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG;
cfg->num_tlv++;
nrmac->ssb_SubcarrierOffset = cfg->ssb_table.ssb_subcarrier_offset.value;
nrmac->ssb_OffsetPointA = cfg->ssb_table.ssb_offset_point_a.value;
LOG_I(NR_MAC,
"ssb_OffsetPointA %d, ssb_SubcarrierOffset %d\n",
cfg->ssb_table.ssb_offset_point_a.value,
cfg->ssb_table.ssb_subcarrier_offset.value);
switch (scc->ssb_PositionsInBurst->present) {
AssertFatal(cfg->ssb_table.ssb_subcarrier_offset.value < 16,
"cannot handle ssb_subcarrier_offset %d resulting from Point A %ld SSB %ld: please increase dl_absoluteFrequencyPointA "
"in the config by 16\n",
cfg->ssb_table.ssb_subcarrier_offset.value,
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB);
cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG;
cfg->num_tlv++;
nrmac->ssb_SubcarrierOffset = cfg->ssb_table.ssb_subcarrier_offset.value;
nrmac->ssb_OffsetPointA = cfg->ssb_table.ssb_offset_point_a.value;
LOG_I(NR_MAC,
"ssb_OffsetPointA %d, ssb_SubcarrierOffset %d\n",
cfg->ssb_table.ssb_offset_point_a.value,
cfg->ssb_table.ssb_subcarrier_offset.value);
switch (scc->ssb_PositionsInBurst->present) {
case 1:
cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] << 24;
cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0;
......@@ -369,19 +678,20 @@ static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch
break;
default:
AssertFatal(1 == 0, "SSB bitmap size value %d undefined (allowed values 1,2,3) \n", scc->ssb_PositionsInBurst->present);
}
}
cfg->ssb_table.ssb_mask_list[0].ssb_mask.tl.tag = NFAPI_NR_CONFIG_SSB_MASK_TAG;
cfg->ssb_table.ssb_mask_list[1].ssb_mask.tl.tag = NFAPI_NR_CONFIG_SSB_MASK_TAG;
cfg->num_tlv += 2;
cfg->ssb_table.ssb_mask_list[0].ssb_mask.tl.tag = NFAPI_NR_CONFIG_SSB_MASK_TAG;
cfg->ssb_table.ssb_mask_list[1].ssb_mask.tl.tag = NFAPI_NR_CONFIG_SSB_MASK_TAG;
cfg->num_tlv += 2;
// logical antenna ports
cfg->carrier_config.num_tx_ant.value = pdsch_AntennaPorts;
AssertFatal(pdsch_AntennaPorts > 0 && pdsch_AntennaPorts < 33, "pdsch_AntennaPorts in 1...32\n");
cfg->carrier_config.num_tx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_TX_ANT_TAG;
// logical antenna ports
int num_pdsch_antenna_ports = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP;
cfg->carrier_config.num_tx_ant.value = num_pdsch_antenna_ports;
AssertFatal(num_pdsch_antenna_ports > 0 && num_pdsch_antenna_ports < 33, "pdsch_AntennaPorts in 1...32\n");
cfg->carrier_config.num_tx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_TX_ANT_TAG;
int num_ssb = 0;
for (int i = 0; i < 32; i++) {
int num_ssb = 0;
for (int i = 0; i < 32; i++) {
cfg->ssb_table.ssb_beam_id_list[i].beam_id.tl.tag = NFAPI_NR_CONFIG_BEAM_ID_TAG;
if ((cfg->ssb_table.ssb_mask_list[0].ssb_mask.value >> (31 - i)) & 1) {
cfg->ssb_table.ssb_beam_id_list[i].beam_id.value = num_ssb;
......@@ -396,26 +706,26 @@ static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch
num_ssb++;
}
cfg->num_tlv++;
}
}
cfg->carrier_config.num_rx_ant.value = pusch_AntennaPorts;
AssertFatal(pusch_AntennaPorts > 0 && pusch_AntennaPorts < 13, "pusch_AntennaPorts in 1...12\n");
cfg->carrier_config.num_rx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_RX_ANT_TAG;
LOG_I(NR_MAC,
"Set RX antenna number to %d, Set TX antenna number to %d (num ssb %d: %x,%x)\n",
cfg->carrier_config.num_tx_ant.value,
cfg->carrier_config.num_rx_ant.value,
num_ssb,
cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,
cfg->ssb_table.ssb_mask_list[1].ssb_mask.value);
AssertFatal(cfg->carrier_config.num_tx_ant.value > 0,
"carrier_config.num_tx_ant.value %d !\n",
cfg->carrier_config.num_tx_ant.value);
cfg->num_tlv++;
cfg->num_tlv++;
// TDD Table Configuration
if (cfg->cell_config.frame_duplex_type.value == TDD) {
cfg->carrier_config.num_rx_ant.value = pusch_AntennaPorts;
AssertFatal(pusch_AntennaPorts > 0 && pusch_AntennaPorts < 13, "pusch_AntennaPorts in 1...12\n");
cfg->carrier_config.num_rx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_RX_ANT_TAG;
LOG_I(NR_MAC,
"Set RX antenna number to %d, Set TX antenna number to %d (num ssb %d: %x,%x)\n",
cfg->carrier_config.num_tx_ant.value,
cfg->carrier_config.num_rx_ant.value,
num_ssb,
cfg->ssb_table.ssb_mask_list[0].ssb_mask.value,
cfg->ssb_table.ssb_mask_list[1].ssb_mask.value);
AssertFatal(cfg->carrier_config.num_tx_ant.value > 0,
"carrier_config.num_tx_ant.value %d !\n",
cfg->carrier_config.num_tx_ant.value);
cfg->num_tlv++;
cfg->num_tlv++;
// TDD Table Configuration
if (cfg->cell_config.frame_duplex_type.value == TDD) {
cfg->tdd_table.tdd_period.tl.tag = NFAPI_NR_CONFIG_TDD_PERIOD_TAG;
cfg->num_tlv++;
if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.ext1 == NULL) {
......@@ -440,7 +750,10 @@ static void config_common(gNB_MAC_INST *nrmac, int pdsch_AntennaPorts, int pusch
LOG_I(NR_MAC, "TDD has been properly configurated\n");
nrmac->tdd_beam_association = (int16_t *)malloc16(periods_per_frame * sizeof(int16_t));
}
}
}
// precoding matrix configuration (to be improved)
cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts);
}
void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config)
......@@ -464,8 +777,7 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c
LOG_I(NR_MAC, "Configuring common parameters from NR ServingCellConfig\n");
int num_pdsch_antenna_ports = config->pdsch_AntennaPorts.N1 * config->pdsch_AntennaPorts.N2 * config->pdsch_AntennaPorts.XP;
config_common(nrmac, num_pdsch_antenna_ports, config->pusch_AntennaPorts, scc);
config_common(nrmac, config->pdsch_AntennaPorts, config->pusch_AntennaPorts, scc);
if (NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MODE_VNF) {
// fake that the gNB is configured in nFAPI mode, which would normally be
......
......@@ -668,8 +668,7 @@ static void pf_dl(module_id_t module_id,
else
sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame);
sched_pdsch->nrOfLayers = get_dl_nrOfLayers(sched_ctrl, current_BWP->dci_format);
sched_pdsch->pm_index =
mac->identity_pm ? 0 : get_pm_index(UE, sched_pdsch->nrOfLayers, mac->radio_config.pdsch_AntennaPorts.XP);
sched_pdsch->pm_index = mac->identity_pm ? 0 : get_pm_index(mac, UE, sched_pdsch->nrOfLayers, mac->radio_config.pdsch_AntennaPorts.XP);
const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx);
const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx);
uint32_t tbs = nr_compute_tbs(Qm,
......
......@@ -129,29 +129,36 @@ uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl,
}
uint16_t get_pm_index(const NR_UE_info_t *UE,
uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
const NR_UE_info_t *UE,
int layers,
int xp_pdsch_antenna_ports) {
if (layers == 1) return 0;
int xp_pdsch_antenna_ports)
{
const NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
const int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id;
const nr_csi_report_t *csi_report = &UE->csi_report_template[report_id];
const int N1 = csi_report->N1;
const int N2 = csi_report->N2;
const int antenna_ports = (N1*N2)<<1;
const int antenna_ports = (N1 * N2) << 1;
if (xp_pdsch_antenna_ports == 1 &&
antenna_ports>1)
if (xp_pdsch_antenna_ports == 1)
return 0; //identity matrix (basic 5G configuration handled by PMI report is with XP antennas)
const int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1;
const int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
LOG_D(NR_MAC,"PMI report: x1 %d x2 %d\n",x1,x2);
LOG_D(NR_MAC,"PMI report: x1 %d x2 %d layers: %d\n", x1, x2, layers);
int prev_layers_size = 0;
for (int i = 1; i < layers; i++)
prev_layers_size += nrmac->precoding_matrix_size[i - 1];
// need to return PM index to matrix initialized in init_DL_MIMO_codebook
// index 0 is for identity matrix
// order of matrices depends on layers to be transmitted
// elements from 1 to n for 1 layer
// elements from n+1 to m for 2 layers etc.
if (antenna_ports == 2)
return x2;
return 1 + prev_layers_size + x2; // 0 for identity matrix
else
AssertFatal(1==0,"More than 2 antenna ports not yet supported\n");
}
......
......@@ -377,7 +377,8 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
const NR_tda_info_t *tda_info,
const int Layers);
uint16_t get_pm_index(const NR_UE_info_t *UE,
uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
const NR_UE_info_t *UE,
int layers,
int xp_pdsch_antenna_ports);
......
......@@ -852,6 +852,7 @@ typedef struct gNB_MAC_INST_s {
uint8_t min_grant_prb;
uint8_t min_grant_mcs;
bool identity_pm;
int precoding_matrix_size[NR_MAX_NB_LAYERS];
nr_mac_rrc_ul_if_t mac_rrc;
f1_config_t f1_config;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment