/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see .
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include "SIMULATION/TOOLS/defs.h"
#include "SIMULATION/RF/defs.h"
#include "PHY/types.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "MAC_INTERFACE/extern.h"
#include "oaisim_config.h"
#ifdef OPENAIR2
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log_if.h"
#include "UTIL/LOG/log_extern.h"
#include "RRC/LITE/extern.h"
#include "PHY_INTERFACE/extern.h"
#include "UTIL/OCG/OCG.h"
#include "UTIL/OMG/omg.h"
#include "UTIL/OPT/opt.h" // to test OPT
#endif
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "oaisim.h"
#define PI 3.1416
#define Am 20
#define MCL (-70) /*minimum coupling loss (MCL) in dB*/
//double sinr[NUMBER_OF_eNB_MAX][2*25];
/*
extern double sinr_bler_map[MCS_COUNT][2][16];
extern double sinr_bler_map_up[MCS_COUNT][2][16];
double SINRpost_eff[301];
extern double MI_map_4qam[3][162];
extern double MI_map_16qam[3][197];
extern double MI_map_64qam[3][227];
*/
// Extract the positions of UE and ENB from the mobility model
void extract_position (node_list* input_node_list, node_desc_t **node_data, int nb_nodes)
{
int i;
for (i=0; ix = input_node_list->node->x_pos;
if (node_data[i]->x <0.0)
node_data[i]->x = 0.0;
node_data[i]->y = input_node_list->node->y_pos;
if (node_data[i]->y <0.0)
node_data[i]->y = 0.0;
LOG_D(OCM, "extract_position: added node_data %d with position X: %f and Y: %f \n", i,input_node_list->node->x_pos, input_node_list->node->y_pos );
input_node_list = input_node_list->next;
} else {
LOG_E(OCM, "extract_position: Null pointer!!!\n");
//exit(-1);
}
}
}
void extract_position_fixed_enb (node_desc_t **node_data, int nb_nodes, frame_t frame)
{
int i;
for (i=0; ix = 0;
node_data[i]->y = 500;
} else if (i == 1 ) {
node_data[i]->x = 866;//
node_data[i]->y = 1000;
} else if (i == 2 ) {
node_data[i]->x = 866;
node_data[i]->y = 0;
}
}
}
void extract_position_fixed_ue (node_desc_t **node_data, int nb_nodes, frame_t frame)
{
int i;
if(frame<50)
for (i=0; ix = 2050;
node_data[i]->y = 1500;
} else {
node_data[i]->x = 2150;
node_data[i]->y = 1500;
}
}
else {
for (i=0; ix = 1856 - (frame - 49);
// if(node_data[i]->x > 2106)
// node_data[i]->x = 2106;
node_data[i]->y = 1813 + (frame - 49);
// if(node_data[i]->y < 1563)
// node_data[i]->y = 1563;
// if( node_data[i]->x == 2106)
// node_data[i]->x = 2106 - (frame - 49);
} else {
node_data[i]->x = 2106 - (frame - 49);
// if(node_data[i]->x < 1856)
// node_data[i]->x = 1856;
node_data[i]->y = 1563 + (frame - 49);
// if(node_data[i]->y < 1813)
// node_data[i]->y = 1813;
}
}
}
}
void init_ue(node_desc_t *ue_data, UE_Antenna ue_ant) //changed from node_struct
{
ue_data->n_sectors = 1;
ue_data->phi_rad = 2 * PI;
ue_data->ant_gain_dBi = ue_ant.antenna_gain_dBi;
ue_data->tx_power_dBm = ue_ant.tx_power_dBm;
ue_data->rx_noise_level = ue_ant.rx_noise_level_dB; //value in db
}
void init_enb(node_desc_t *enb_data, eNB_Antenna enb_ant) //changed from node_struct
{
int i;
double sect_angle[3]= {0,2*PI/3,4*PI/3};
enb_data->n_sectors = enb_ant.number_of_sectors;
for (i=0; in_sectors; i++)
enb_data->alpha_rad[i] = sect_angle[i]; //enb_ant.alpha_rad[i];
enb_data->phi_rad = enb_ant.beam_width_dB;
enb_data->ant_gain_dBi = enb_ant.antenna_gain_dBi;
enb_data->tx_power_dBm = enb_ant.tx_power_dBm;
enb_data->rx_noise_level = enb_ant.rx_noise_level_dB;
}
void calc_path_loss(node_desc_t* enb_data, node_desc_t* ue_data, channel_desc_t *ch_desc, Environment_System_Config env_desc, double **Shad_Fad)
{
double dist;
double path_loss;
double gain_max;
double gain_sec[3];
double alpha, theta;
int count;
dist = sqrt(pow((enb_data->x - ue_data->x), 2) + pow((enb_data->y - ue_data->y), 2));
path_loss = env_desc.fading.free_space_model_parameters.pathloss_0_dB -
10*env_desc.fading.free_space_model_parameters.pathloss_exponent * log10(dist/1000);
LOG_D(OCM,"dist %f, Path loss %f\n",dist,ch_desc->path_loss_dB);
/* Calculating the angle in the range -pi to pi from the slope */
alpha = atan2((ue_data->y - enb_data->y),(ue_data->x - enb_data->x));
if (alpha < 0)
alpha += 2*PI;
//printf("angle in radians is %lf\n", ue_data[UE_id]->alpha_rad[eNB_id]);
ch_desc->aoa = alpha;
ch_desc->random_aoa = 0;
if (enb_data->n_sectors==1) //assume omnidirectional antenna
gain_max = 0;
else {
gain_max = -1000;
for(count = 0; count < enb_data->n_sectors; count++) {
theta = enb_data->alpha_rad[count] - alpha;
/* gain = -min(Am , 12 * (theta/theta_3dB)^2) */
gain_sec[count] = -(Am < (12 * pow((theta/enb_data->phi_rad),2)) ? Am : (12 * pow((theta/enb_data->phi_rad),2)));
if (gain_sec[count]>gain_max) //take the sector that we are closest too (or where the gain is maximum)
gain_max = gain_sec[count];
}
}
path_loss += enb_data->ant_gain_dBi + gain_max + ue_data->ant_gain_dBi;
if (Shad_Fad!=NULL)
path_loss += Shad_Fad[(int)ue_data->x][(int)ue_data->y];
ch_desc->path_loss_dB = MCL < path_loss ? MCL : path_loss;
//LOG_D(OCM,"x_coordinate\t%f\t,y_coordinate\t%f\t, path_loss %f\n",ue_data->x,ue_data->y,ch_desc->path_loss_dB);
}
void init_snr(channel_desc_t* eNB2UE, node_desc_t *enb_data, node_desc_t *ue_data, double* sinr_dB, double* N0, uint8_t transmission_mode, uint16_t q, uint8_t dl_power_off, uint16_t nb_rb)
{
double thermal_noise,abs_channel,channelx, channely,channelx_i, channely_i ;
int count;
int aarx,aatx;
uint8_t qq;
/* Thermal noise is calculated using 10log10(K*T*B) K = Boltzmann's constant T = room temperature B = bandwidth*/
thermal_noise = -174 + 10*log10(15000); //per RE; value in dBm
//for (aarx=0; aarxnb_rx; aarx++)
*N0 = thermal_noise + ue_data->rx_noise_level;
LOG_D(OCM,"Path loss %lf, noise (N0) %lf, signal %lf, snr %lf\n",
eNB2UE->path_loss_dB,
thermal_noise + ue_data->rx_noise_level,
enb_data->tx_power_dBm + eNB2UE->path_loss_dB,
enb_data->tx_power_dBm + eNB2UE->path_loss_dB - (thermal_noise + ue_data->rx_noise_level));
if(transmission_mode == 5 && dl_power_off==1)
transmission_mode = 6;
switch(transmission_mode) {
case 1:
//printf ("coupling factor is %lf\n", coupling);
for (count = 0; count < (12 * nb_rb); count++) {
sinr_dB[count] = enb_data->tx_power_dBm
+ eNB2UE->path_loss_dB
- (thermal_noise + ue_data->rx_noise_level)
+ 10 * log10 (pow(eNB2UE->chF[0][count].x, 2)
+ pow(eNB2UE->chF[0][count].y, 2));
//printf("sinr_dB[%d]: %1f\n",count,sinr_dB[count]);
//printf("Dl_link SNR for res. block %d is %lf\n", count, sinr[eNB_id][count]);
}
break;
case 2:
for (count = 0; count < (12 * nb_rb); count++) {
abs_channel=0;
for (aarx=0; aarxnb_rx; aarx++) {
for (aatx=0; aatxnb_tx; aatx++) {
abs_channel += (pow(eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x, 2) + pow(eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y, 2));
}
}
sinr_dB[count] = enb_data->tx_power_dBm
+ eNB2UE->path_loss_dB
- (thermal_noise + ue_data->rx_noise_level)
+ 10 * log10 (abs_channel/2);
// printf("sinr_dB[%d]: %1f\n",count,sinr_dB[count]);
}
break;
case 5:
for (count = 0; count < (12 * nb_rb); count++) {
channelx=0;
channely=0;
channelx_i=0;
channely_i=0;
qq = (q>>(((count/12)>>2)<<1))&3;
//printf("pmi_alloc %d: rb %d, pmi %d\n",q,count/12,qq);
// qq = q;
for (aarx=0; aarxnb_rx; aarx++) {
for (aatx=0; aatxnb_tx; aatx++) {
switch(qq) {
case 0:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channelx_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channelx_i -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely_i -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
}
break;
case 1:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channelx_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channelx_i += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely_i += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
}
break;
case 2:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channelx_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channely += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channelx_i += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channely_i -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
}
break;
case 3:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channelx_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely_i = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channely -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channelx_i -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channely_i += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
}
break;
default:
msg("Problem in SINR Calculation for TM5 \n");
break;
}//switch(q)
}//aatx
}//aarx
/* sinr_dB[count] = enb_data->tx_power_dBm
+ eNB2UE->path_loss_dB
- (thermal_noise + ue_data->rx_noise_level)
+ 10 * log10 ((pow(channelx,2) + pow(channely,2))/2) - 10 * log10 ((pow(channelx_i,2) + pow(channely_i,2))/2);
*/
sinr_dB[count] = enb_data->tx_power_dBm
+ eNB2UE->path_loss_dB
- (thermal_noise + ue_data->rx_noise_level)
+ 10 * log10 ((pow(channelx,2) + pow(channely,2))) - 10 * log10 ((pow(channelx_i,2) + pow(channely_i,2))) - 3; // 3dB is subtracted as the tx_power_dBm is to be adjusted on per user basis
// printf("sinr_dB[%d]: %1f\n",count,sinr_dB[count]);
}
break;
case 6:
for (count = 0; count < (12 * nb_rb); count++) {
channelx=0;
channely=0;
qq = (q>>(((count/12)>>2)<<1))&3;
//printf("pmi_alloc %d: rb %d, pmi %d\n",q,count/12,qq);
// qq = q;
for (aarx=0; aarxnb_rx; aarx++) {
for (aatx=0; aatxnb_tx; aatx++) {
switch(qq) {
case 0:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
}
break;
case 1:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
}
break;
case 2:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channely += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
}
break;
case 3:
if (channelx==0 || channely==0) {
channelx = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
channely = eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
} else {
channelx += eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].y;
channely -= eNB2UE->chF[aarx+(aatx*eNB2UE->nb_rx)][count].x;
}
break;
default:
msg("Problem in SINR Calculation for TM6 \n");
break;
}//switch(q)
}//aatx
}//aarx
sinr_dB[count] = enb_data->tx_power_dBm
+ eNB2UE->path_loss_dB
- (thermal_noise + ue_data->rx_noise_level)
+ 10 * log10 ((pow(channelx,2) + pow(channely,2))/2);
// printf("sinr_dB[%d]: %1f\n",count,sinr_dB[count]);
}
break;
default:
msg("Problem in SINR Initialization in sinr_sim.c\n");
break;
}//switch
}//function ends
#ifdef PHY_ABSTRACTION_UL
void init_snr_up(channel_desc_t* UE2eNB, node_desc_t *enb_data, node_desc_t *ue_data, double* sinr_dB, double* N0,uint16_t nb_rb,uint16_t fr_rb)
{
int return_value;
double thermal_noise;
int count;
int aarx;
// nb_rb = phy_vars_eNB->ulsch_eNB[UE_id]->harq_processes[harq_pid]->nb_rb;
/* Thermal noise is calculated using 10log10(K*T*B) K = Boltzmann's constant T = room temperature B = bandwidth */
thermal_noise = -174 + 10*log10(UE2eNB->sampling_rate*1e6); //value in dBm
*N0 = thermal_noise + enb_data->rx_noise_level;//? all the element have the same noise level?????
double lambda ;
double residual;
double sinrlin;
double residual_db;
residual = 0 ;
int ccc;
/*
for (count = (fr_rb*12) ; count < (12 * (fr_rb+nb_rb)); count++)
{
residual += ( 1 / ( pow((UE2eNB -> chF[0][count].x),2) + pow((UE2eNB -> chF[0][count].y),2)));
}
*///sinreff(nn) = ((sum((1/p).*(snrm(nn,:)./(snrm(nn,:)+1)),2).^(-1) )-1).^-1;
sinrlin = 0 ;
lambda = 0;
////First calculate SINRs of subcarriers just like OFDM
for (count = (fr_rb*12) ; count < (12 * (fr_rb+nb_rb)); count++) {
sinr_dB[count] = ue_data->tx_power_dBm
+ UE2eNB->path_loss_dB
- (thermal_noise + enb_data->rx_noise_level)
+ 10 * log10 (pow(UE2eNB->chF[0][count].x, 2)
+ pow(UE2eNB->chF[0][count].y, 2));
}
//Then apply formula :
if(nb_rb > 0) {
//calculate lambdas and fill the same with all but just use one of them when necessary for abstraction
for (count = fr_rb*12; count < (12 * (fr_rb+nb_rb)); count++) {
sinrlin = pow((sinr_dB[count]/10),10); // convert SINR to linear
lambda += (sinrlin / (sinrlin + 1)) ;
}
for (count = fr_rb*12; count < (12 * (fr_rb+nb_rb)); count++) {
sinr_dB[count] = pow(lambda,2) /(((nb_rb)*lambda)-pow(lambda,2)) ;
sinr_dB[count] = 10*log10(sinr_dB[count]) ; //save it in db
}
printf("tx_power %g, path_loss %g, sinr_dB[0] %g\n",ue_data->tx_power_dBm ,UE2eNB->path_loss_dB,sinr_dB[count-1]);
for (ccc = 0; ccc < 301 ; ccc++ ) {
SINRpost_eff[ccc] = 0;
SINRpost_eff[ccc] = sinr_dB[ccc];
}
}
}//function ends
#endif
void calculate_sinr(channel_desc_t* eNB2UE, node_desc_t *enb_data, node_desc_t *ue_data, double *sinr_dB, uint16_t nb_rb)
{
double sir, thermal_noise;
short count;
/* Thermal noise is calculated using 10log10(K*T*B) K = Boltzmann's constant T = room temperature B = bandwidth */
thermal_noise = -174 + 10*log10(15000); //per RE, value in dBm
for (count = 0; count < 12 * nb_rb; count++) {
sir = enb_data->tx_power_dBm
+ eNB2UE->path_loss_dB
- (thermal_noise + ue_data->rx_noise_level)
+ 10 * log10 (pow(eNB2UE->chF[0][count].x, 2)
+ pow(eNB2UE->chF[0][count].y, 2));
if (sir > 0)
sinr_dB[count] -= sir;
//printf("*****sinr% lf \n",sinr_dB[count]);
}
}
void get_beta_map()
{
char *file_path = NULL;
//int table_len = 0;
int t,u;
int mcs = 0;
char *sinr_bler;
char buffer[1000];
FILE *fp;
double perf_array[13];
file_path = (char*) malloc(512);
for (mcs = 0; mcs < MCS_COUNT; mcs++) {
snprintf( file_path, 512, "%s/SIMULATION/LTE_PHY/BLER_SIMULATIONS/AWGN/AWGN_results/bler_tx1_chan18_nrx1_mcs%d.csv", getenv("OPENAIR1_DIR"), mcs );
fp = fopen(file_path,"r");
if (fp == NULL) {
LOG_E(OCM,"ERROR: Unable to open the file %s! Exitng.\n", file_path);
exit(-1);
}
// else {
if (fgets (buffer, 1000, fp) != NULL) {
if (fgets (buffer, 1000, fp) != NULL) {
table_length[mcs] = 0;
while (!feof (fp)) {
u = 0;
sinr_bler = strtok (buffer, ";");
while (sinr_bler != NULL) {
perf_array[u] = atof (sinr_bler);
u++;
sinr_bler = strtok (NULL, ";");
}
if ((perf_array[4] / perf_array[5]) < 1) {
sinr_bler_map[mcs][0][table_length[mcs]] = perf_array[0];
sinr_bler_map[mcs][1][table_length[mcs]] = (perf_array[4] / perf_array[5]);
table_length[mcs]++;
if (table_length[mcs]>MCS_TABLE_LENGTH_MAX) {
LOG_E(OCM,"Error reading MCS table. Increase MCS_TABLE_LENGTH_MAX (mcs %d)!\n",mcs);
exit(-1);
}
}
if (fgets (buffer, 1000, fp) != NULL) {
}
}
}
}
fclose(fp);
// }
LOG_D(OCM,"Print the table for mcs %d\n",mcs);
for (t = 0; t