Network planning with 5G TDD

Detailed Description

This is an example of how to use the WinProp API for network planning with the 5G TDD protocol. The full example is distributed with the installation.
#include <stdio.h>
#include <string>
#include <iostream>

#include "network_planning_5g_tdd.h"

#ifndef API_DATA_FOLDER
#define API_DATA_FOLDER "../../api/winprop/data/"
#endif // !API_DATA_FOLDER

#define SERVICES_5G 13
#define MAX_CELLS 1

int main(int argc, char** argv)
{

	int Error = 0;
	int ProjectHandle = 0;
	int ParaValueInt = 0;
	double ParaValueDouble = 0.;

	// ------ General and Propagation and Network Planing Parameters ------ //
	WinProp_ParaMain GeneralParameters;
	WinProp_Pattern  WinPropPattern[MAX_CELLS];
	WinProp_Antenna  Antenna[MAX_CELLS];
	WinProp_Carrier  Carrier[MAX_CELLS];

	// Propagation results 
	WinProp_Result   PropResults[MAX_CELLS];

	// Prediction heights 
	int              NrPredictionHeights = 1;
	double           PredictionHeights[1] = { 1.5 };

	// ---------------------- Initialisation of parameters ---------------- //
	WinProp_Structure_Init_ParameterMain(&GeneralParameters);

	for (int cell = 0; cell < MAX_CELLS; cell++)
	{
		WinProp_Structure_Init_Pattern(&WinPropPattern[cell]);
		WinProp_Structure_Init_Antenna(&Antenna[cell]);
		WinProp_Structure_Init_Carrier(&Carrier[cell]);
		WinProp_Structure_Init_Result(&PropResults[cell]);
	}

	// ---------------- Definition of parameters -------------------------- //
	// Definition of scenario. 
	const char* my_odb_database = API_DATA_FOLDER "outdoor/Helsinki"; // name of .oib database without extensions 
	GeneralParameters.ScenarioMode = SCENARIOMODE_URBAN; // Urban prediction
	GeneralParameters.PredictionModelUrban = PREDMODEL_IRT; // Use IRT Model
	GeneralParameters.BuildingsMaterialsInd = 1;            // Individual material properties for buildings
	GeneralParameters.VegetationMode = VEGETATION_BUILDING; // vegetation from building database
	GeneralParameters.VegetationPropertiesInd = 1;          // Individual material properties for vegetation

	// Definition of prediction area.
	GeneralParameters.UrbanLowerLeftX = 385828.35;
	GeneralParameters.UrbanLowerLeftY = 6672097.054;
	GeneralParameters.UrbanUpperRightX = 386012.35;
	GeneralParameters.UrbanUpperRightY = 6672356.054;

	// Copy coordinates to prediction area of second model (not yet used).
	GeneralParameters.RuralLowerLeftX = GeneralParameters.UrbanLowerLeftX;
	GeneralParameters.RuralLowerLeftY = GeneralParameters.UrbanLowerLeftY;
	GeneralParameters.RuralUpperRightX = GeneralParameters.UrbanUpperRightX;
	GeneralParameters.RuralUpperRightY = GeneralParameters.UrbanUpperRightY;

	// Size of matrix with results.
	GeneralParameters.Resolution = 1.0;                        // Resolution in meter
	GeneralParameters.NrLayers = NrPredictionHeights;          // Number of prediction heights
	GeneralParameters.PredictionHeights = PredictionHeights;   // Prediction height in meter

	// Building vector data and topography.
	GeneralParameters.BuildingsMode = BUILDINGSMODE_IRT; // load a .oib database 
	sprintf(GeneralParameters.BuildingsName, "%s", my_odb_database);

	// Break point parameters
	GeneralParameters.BreakpointMode = BREAKPOINT_DEFAULT;
	GeneralParameters.BreakpointFactor = 4.;
	GeneralParameters.BreakpointOffset = 0;

	// Selection of paths
	GeneralParameters.MaxPathLossEnabled = 1;
	GeneralParameters.MaxPathLoss = 200.f;
	GeneralParameters.MaxDynamicPathsEnabled = 1;
	GeneralParameters.MaxDynamicPaths = 100.f;
	GeneralParameters.MaxNumberPathsUsed = 1;
	GeneralParameters.MaxNumberPaths = 20;

	// Antenna patten
	WinPropPattern[0].Mode = PATTERN_MODE_FILE;   // Load pattern from file
	char PatternFileName[500];
	sprintf(PatternFileName, "%s", API_DATA_FOLDER "antennas/3750MHz_18dBi.msi");
	WinPropPattern[0].Filename = PatternFileName; // Pattern file

	// Desired propagation results in WinProp result format
	WinProp_Propagation_Results OutputResults;
	WinProp_Structure_Init_Propagation_Results(&OutputResults);
	char ResultPath[500];
	sprintf(ResultPath, "%s", API_DATA_FOLDER "output/propagation");
	OutputResults.ResultPath = ResultPath; // Output data directory 
	OutputResults.Delay = 1;
	OutputResults.StatusLOS = 1;
	OutputResults.AdditionalResultsASCII = 1;
	GeneralParameters.OutputResults = &OutputResults;

	// Callback functions.
    WinProp_Callback Callback;
    WinProp_Structure_Init_Callback(&Callback);
	Callback.Percentage = CallbackProgress;
	Callback.Message = CallbackMessage;
	Callback.Error = CallbackError;

	//--------------------------------------------------------------------------
	// Compute wave propagation for cells
	//--------------------------------------------------------------------------

	// ----------------  Define IRT parameters -------------------------- //
	Model_UrbanIRT ParameterIRT;
	WinProp_Structure_Init_Model_UrbanIRT(&ParameterIRT);

	// set path loss exponents 
	ParameterIRT.BreakpointExponentBeforeLOS = 2.3;
	ParameterIRT.BreakpointExponentAfterLOS = 3.3;
	ParameterIRT.BreakpointExponentBefore = 2.5;
	ParameterIRT.BreakpointExponentAfter = 3.3;

	// Number of interactions
	ParameterIRT.MaxReflections = 2;
	ParameterIRT.MaxDiffractions = 1;
	ParameterIRT.MaxScatterings = 0;
	ParameterIRT.MaxSumReflDiff = 2;

	// Superposition and diffraction mode
	ParameterIRT.Superposition = 0;
	ParameterIRT.DiffractionModel = 'e';
	ParameterIRT.PostProcessingMode = 0;
	ParameterIRT.Postprocessing = 0;
	ParameterIRT.FreeSpaceCancel = 0;

	// --------------------------  antennas  -------------------------------- //
	// Position and configuration of the antennas (cells).
	char AntennaName[MAX_CELLS][500] = { "Cell_1"};
	double SiteX[MAX_CELLS] = { 385925.79 };
	double SiteY[MAX_CELLS] = { 6672148.00 };
	double SiteZ[MAX_CELLS] = { 15. };
	double Power[MAX_CELLS] = { 15. }; // Power in dBm
	double Azmith[MAX_CELLS] = { 0. };
	double Downtilt[MAX_CELLS] = { 10. };
	double Frequency[MAX_CELLS] = { 3750.0 }; // same frequencies in MHz as will defined for the carriers (for network planning)
	int AntennaCarrier[MAX_CELLS] = { 1 };

	for (int cell = 0; cell < MAX_CELLS; cell++)
	{
		// set antenna pattern
		Antenna[cell].Pattern = &WinPropPattern[cell];

		// Set antenna properties now.
		AntennaPropertiesSet(&Antenna[cell], SiteX[cell], SiteY[cell], SiteZ[cell], Frequency[cell], AntennaName[cell],
			Power[cell], WINPROP_POWER_OUTPUT, WINPROP_MODEL_IRT, Azmith[cell], Downtilt[cell], cell + 1);

		Carrier[cell].CarrierID = AntennaCarrier[cell];
		Carrier[cell].NrAntennaBeams = 1;
		Carrier[cell].SymbolsPerSlot = 14;
		Carrier[cell].Numerology = 1;
		Carrier[cell].TDD_Slots_DL = 7;
		Carrier[cell].TDD_Slots_UL = 7;
		Carrier[cell].TDD_Slots_Flex = 0;
		Carrier[cell].BeamGainCtrlServer = 0.;
		Carrier[cell].BeamGainCtrlInterferer = 0.;
		Carrier[cell].BeamGainDataServer = 0.;
		Carrier[cell].BeamGainDataInterferer = 0.;

		CarrierPropertiesSet(&Antenna[cell], &Carrier[cell]);

		/*--------------------- Compute outdoor prediction ------------------------*/
		Error = OutdoorPlugIn_ComputePrediction(&Antenna[cell], &GeneralParameters, NULL, 0, &ParameterIRT, NULL, NULL, NULL, &Callback, &PropResults[cell], NULL, NULL, NULL);

		/*---------------------- write propagation results ------------------------*/
		if (Error == 0)
		{
			char NameForOutput[200];
			sprintf(NameForOutput, "%s%s%s%s", API_DATA_FOLDER, "output/propagation/", Antenna[cell].Name, ".txt");

			write_ascii(&PropResults[cell], NameForOutput);
		}
		else
		{
			/* Error during prediction. Print error message. */
			CallbackError(GeneralParameters.ErrorMessageMain, Error);
		}
	}


	// -------------------- Network Planning Project ----------------------- /

	// Create a new network planning project based on 5G TDD air interface                           
	if (Error == 0)
	{
		Error = WinProp_Net_Project_Open(&ProjectHandle, NET_AIRINTERFACE_5G_TDD_GENERIC, NULL);
	}

	// Add all propagation maps which have been computed.
	if (Error == 0)
	{
		int MapIndex[MAX_CELLS];
		for (int Count = 0; Count < MAX_CELLS; Count++)
		{
			if (Error == 0)
			{
				Error = WinProp_Net_PropagationMap_Add(ProjectHandle, &MapIndex[Count], &Antenna[Count], &PropResults[Count]);
			}
		}
	}

	// Set a name for the project.
	if (Error == 0)
	{
		char ProjectName[200];
		sprintf(ProjectName, "%s", "TDD-5G");
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_PROJECTNAME, NULL, NULL, ProjectName);
	}

	// -------------------  numerology  ----------------------- //
	// Set numerology and bandwidth
	if (Error == 0)
	{
		ParaValueInt = NET_PARA_5G_NUMEROLOGY1_100MHZ_FR1;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_BANDWIDTH_MODE_5G, NULL, &ParaValueInt, NULL);
	}

	// -------------------  TDD  ----------------------- //
	if (Error == 0)
	{
		ParaValueInt = 1; // TDD mode
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_DUPLEX_SUBMODE, NULL, &ParaValueInt, NULL);

	}

	if (Error == 0)
	{
		ParaValueInt = 3; // TDD properties specified for each carrier individually
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_TDD_VARIABLE_SWITCH, NULL, &ParaValueInt, NULL);
	}

	// --------------------------  Carriers  -------------------------------- //
	// Add carriers in n1 band.
	if (Error == 0)
	{
		double FrequencyUL = 0.;
		double FrequencyDL = 0.;
		double CarrierSeparation = 100.;
		for (int CurrentCarrier = 0; CurrentCarrier < 1; CurrentCarrier++)
		{
			FrequencyUL = 3750.0 + (CurrentCarrier * CarrierSeparation);
			FrequencyDL = 3750.0 + (CurrentCarrier * CarrierSeparation);
			Error = WinProp_Net_Carrier_Add(ProjectHandle, CurrentCarrier + 1);

			Error = WinProp_Net_Carrier_Para_Set(
				ProjectHandle, CurrentCarrier + 1, NET_PARA_CARRIER_FREQ_DL, &FrequencyDL, NULL, NULL);
			Error = WinProp_Net_Carrier_Para_Set(
				ProjectHandle, CurrentCarrier + 1, NET_PARA_CARRIER_FREQ_UL, &FrequencyUL, NULL, NULL);
		}
	}

	// Check if number of carriers is correct. 
	if (Error == 0)
	{
		int NrCarriers = 0;
		Error = WinProp_Net_Project_Para_Get(ProjectHandle, NET_PARA_CARRIERS, NULL, &NrCarriers, NULL);
		if (Error == 0)
		{
			if (NrCarriers != 1)
				Error = 1;
		}
	}

	// -------------------------  Transmission modes  --------------------------- //
	// Define 5G transmission modes
	if (Error == 0)
	{
		const char* TransmissionMode_Name[SERVICES_5G] = {
											 "00 - QPSK - R 120",
											 "01 - QPSK - R 193",
											 "02 - QPSK - R 308",
											 "03 - QPSK - R 449",
											 "04 - QPSK - R 602",
											 "06 - 16 QAM - R 378",
											 "07 - 16 QAM - R 490",
											 "08 - 16 QAM - R 658",
											 "09 - 64 QAM - R 466",
											 "10 - 64 QAM - R 666",
											 "11 - 64 QAM - R 873",
											 "12 - 256 QAM - R 797",
											 "13 - 256 QAM - R 948" };
		double              TransmissionMode_Bitrate[SERVICES_5G] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
		double              TransmissionMode_SNIR[SERVICES_5G] = { -3.0, -2.0, -1.0, 0.0, 2.0, 7.0, 10.0, 12.0, 13.0, 16.0, 18.0, 22.0,  27.0 };
		int                 TransmissionMode_Coderate_K[SERVICES_5G] = { 120, 193, 308, 449, 602, 378, 490, 658, 466, 666, 873, 797, 948 };
		int                 TransmissionMode_Coderate_N[SERVICES_5G] = { 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 };
		int                 TransmissionMode_MCS[SERVICES_5G] = { 2, 2, 2, 2, 2, 4, 4, 4, 6, 6, 6, 8, 8 };
		double              TransmissionMode_Backoff[SERVICES_5G] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 3.0, 3.0, 3.0, 3.0 };
		int                 TransmissionMode_Resource_Blocks_DL[SERVICES_5G] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
		int                 TransmissionMode_Resource_Blocks_UL[SERVICES_5G] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ,1, 1, 1 };
		double              TransmissionMode_Overhead_Ratio_DL[SERVICES_5G] = { 14., 14., 14., 14., 14., 14., 14., 14., 14., 14., 14., 14. , 14. };
		double              TransmissionMode_Overhead_Ratio_UL[SERVICES_5G] = { 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8. };

		for (int CurrentService = 0; CurrentService < SERVICES_5G; CurrentService++)
		{
			// Add new service. 
			char ServiceName[100];
			sprintf(ServiceName, "%s", TransmissionMode_Name[CurrentService]);
			Error = WinProp_Net_TransmissionMode_Add(ProjectHandle, ServiceName, CurrentService);

			// Set position/priority.
			ParaValueInt = SERVICES_5G - CurrentService;
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_POSITION, NULL, &ParaValueInt, NULL);

			// Set bitrate.
			ParaValueDouble = TransmissionMode_Bitrate[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_BITRATE_DL, &ParaValueDouble, NULL, NULL);
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_BITRATE_UL, &ParaValueDouble, NULL, NULL);

			// Set code rate.
			ParaValueInt = TransmissionMode_Coderate_K[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_CODERATE_K_DL, NULL, &ParaValueInt, NULL);
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_CODERATE_K_UL, NULL, &ParaValueInt, NULL);

			ParaValueInt = TransmissionMode_Coderate_N[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_CODERATE_N_DL, NULL, &ParaValueInt, NULL);
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_CODERATE_N_UL, NULL, &ParaValueInt, NULL);

			// Set number of resource blocks.
			ParaValueInt = TransmissionMode_Resource_Blocks_DL[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_RESOURCE_BLOCKS_DL, NULL, &ParaValueInt, NULL);
			ParaValueInt = TransmissionMode_Resource_Blocks_UL[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_RESOURCE_BLOCKS_UL, NULL, &ParaValueInt, NULL);

			// Set overhead ratio. 
			ParaValueDouble = TransmissionMode_Overhead_Ratio_UL[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_OVERHEAD_RATIO_UL, &ParaValueDouble, NULL, NULL);
			ParaValueDouble = TransmissionMode_Overhead_Ratio_DL[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_OVERHEAD_RATIO_DL, &ParaValueDouble, NULL, NULL);

			// Set required SNIR.
			ParaValueDouble = TransmissionMode_SNIR[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_SNIR_DL, &ParaValueDouble, NULL, NULL);
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_SNIR_UL, &ParaValueDouble, NULL, NULL);

			// Set modulation scheme.
			ParaValueInt = TransmissionMode_MCS[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_MODULATION_UL, NULL, &ParaValueInt, NULL);
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_MODULATION_DL, NULL, &ParaValueInt, NULL);

			// Set power backoff. 
			ParaValueDouble = TransmissionMode_Backoff[CurrentService];
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_POWER_BACKOFF_UL, &ParaValueDouble, NULL, NULL);
			Error = WinProp_Net_TransmissionMode_Para_Set(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_POWER_BACKOFF_DL, &ParaValueDouble, NULL, NULL);

			// Get bitrate in kBit/s for current transmission mode. Bitrate is automatically computed based
			// on parameters previously set and general air interface parameters.
			Error = WinProp_Net_TransmissionMode_Para_Get(
				ProjectHandle, CurrentService, NET_PARA_TRANS_MODE_BITRATE_DL, &ParaValueDouble, NULL, NULL);
			TransmissionMode_Bitrate[CurrentService] = ParaValueDouble;
		}
	}

	// Check if number of services is correct.
	if (Error == 0)
	{
		int NrServices = 0;
		Error = WinProp_Net_Project_Para_Get(ProjectHandle, NET_PARA_SERVICES, NULL, &NrServices, NULL);
		if (Error == 0)
		{
			if (NrServices != SERVICES_5G)
				Error = 1;
		}
	}

	// --------------------------  Project parameters  -------------------------- //
	
	// Set resolution for result matrix.
	if (Error == 0)
	{
		ParaValueDouble = GeneralParameters.Resolution;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_RESOLUTION, &ParaValueDouble, NULL, NULL);
	}
	// Set the simulation area
	if (Error == 0)
	{
		ParaValueDouble = GeneralParameters.UrbanLowerLeftX;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_AREA_LL_X, &ParaValueDouble, NULL, NULL);
	}
	if (Error == 0)
	{
		ParaValueDouble = GeneralParameters.UrbanLowerLeftY;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_AREA_LL_Y, &ParaValueDouble, NULL, NULL);
	}
	if (Error == 0)
	{
		ParaValueDouble = GeneralParameters.UrbanUpperRightX;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_AREA_UR_X, &ParaValueDouble, NULL, NULL);
	}
	if (Error == 0)
	{
		ParaValueDouble = GeneralParameters.UrbanUpperRightY;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_AREA_UR_Y, &ParaValueDouble, NULL, NULL);
	}

	// Set paths for additional output in WinProp file format.
	if (Error == 0)
	{
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_OUTPUT_WINPROP, NULL, NULL, API_DATA_FOLDER "output/network");
	}

	// ------------------------  Cell assignment   ------------------------------ //
	if (Error == 0)
	{
		int IntValue = 0; // highest Rx power for all carries mode
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_CELL_ASSIGNMENT_MODE, NULL, &IntValue, NULL);
	}

	// Set Min required SNIR
	if (Error == 0)
	{
		ParaValueDouble = -5.4;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_CELL_ASSIGNMENT_MIN_REQ_SNIR, &ParaValueDouble, NULL, NULL);
	}

	// Set Min required power
	if (Error == 0)
	{
		ParaValueDouble = -95.;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_CELL_ASSIGNMENT_MIN_REQ_POWER, &ParaValueDouble, NULL, NULL);
	}


	// -----------------------  OFDM parameters  -------------------------------- //
	// Set control sub-carriers 
	if (Error == 0)
	{
		ParaValueInt = 2500;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_SUBCARRIERS_CONTROL, NULL, &ParaValueInt, NULL);
	}

	// Set reference sub-carriers 
	if (Error == 0)
	{
		ParaValueInt = 500;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_SUBCARRIERS_REFERENCE, NULL, &ParaValueInt, NULL);
	}

	// Set Guard sub-carriers
	if (Error == 0)
	{
		ParaValueInt = 29;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_SUBCARRIERS_GUARD, NULL, &ParaValueInt, NULL);
	}

	// Set data symbols 
	if (Error == 0)
	{
		ParaValueInt = 10;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_SYMBOLS_DATA, NULL, &ParaValueInt, NULL);
	}

	// Set control symbols 
	if (Error == 0)
	{
		ParaValueInt = 1;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_SYMBOLS_CONTROL, NULL, &ParaValueInt, NULL);
	}

	// Set reference symbols
	if (Error == 0)
	{
		ParaValueInt = 3;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_SYMBOLS_REFERENCE, NULL, &ParaValueInt, NULL);
	}

	// Set FFT order 
	if (Error == 0)
	{
		ParaValueInt = 4096;
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_FFT_SIZE, NULL, &ParaValueInt, NULL);
	}

	// Desired network planning results in WinProp result format
	if (Error == 0)
	{
		Error = WinProp_Net_Project_Result_Switch(ProjectHandle, NET_RESULT_BEST_SERVER, 1);
		Error = WinProp_Net_Project_Result_Switch(ProjectHandle, NET_RESULT_MAX_DATARATE, 1);
		Error = WinProp_Net_Project_Result_Switch(ProjectHandle, NET_RESULT_MAX_THROUGHPUT, 1);
		Error = WinProp_Net_Project_Result_Switch(ProjectHandle, NET_RESULT_SNIR, 1);
	}

	//--------------------------------------------------------------------------
	//  Compute network planning results
	//--------------------------------------------------------------------------
	if (Error == 0)
	{
		char HeightString[200];
		sprintf(HeightString, "%s", "");

		// Generate string with height values, e.g. a string like "1.5 2.5 3.5". 
		for (int Height = 0; Height < NrPredictionHeights; Height++)
		{
			// Add current height to string.
			sprintf(HeightString, "%s%.2f ", HeightString, PredictionHeights[Height]);
		}

		// Send heights to WinProp API.
		Error = WinProp_Net_Project_Para_Set(ProjectHandle, NET_PARA_HEIGHT_MULTIPLE, NULL, NULL, HeightString);

		// Start network computation.
		if (Error == 0)
		{
			Error = WinProp_Net_Project_Compute(ProjectHandle, &Callback);
		}
	}

	// ------------------------------------------------------------------------
	// Retrieve  results 
	// ------------------------------------------------------------------------
	// As an example: retrieve max. throughput (kbps) per pixel.
	if (Error == 0)
	{
		WinProp_Result* MaxThroughput = NULL;
		Error = WinProp_Net_NetworkMap_Get(ProjectHandle, -1, NET_RESULT_MAX_THROUGHPUT, &MaxThroughput);

		// Write max. throughput result to ASCII file.
		if (Error == 0)
		{
			char NameForOutput[200];
			sprintf(NameForOutput, "%s%s", API_DATA_FOLDER, "output/Network/Max Throughput DownLink.txt");
			write_ascii(MaxThroughput, NameForOutput);
		}

	}

	// As another example: retrieve SNIR (dB) per pixel.
	if (Error == 0)
	{
		WinProp_Result* MaxSNIR = NULL;
		Error = WinProp_Net_NetworkMap_Get(ProjectHandle, -1, NET_RESULT_SNIR, &MaxSNIR);

		// Write max. throughput result to ASCII file.
		if (Error == 0)
		{
			char NameForOutput[200];
			sprintf(NameForOutput, "%s%s", API_DATA_FOLDER, "output/Network/Max SNIR.txt");
			write_ascii(MaxSNIR, NameForOutput);
		}
	}

	// ------------------------------------------------------------------------
	// Free memory
	// ------------------------------------------------------------------------
	for (int Count = 0; Count < MAX_CELLS; Count++)
	{
		// Free propagation results.
		WinProp_FreeResult(&PropResults[Count]);
	}

	// Close network project.
	Error = WinProp_Net_Project_Close(ProjectHandle);

	return 0;
}

int _STD_CALL CallbackMessage(const char* Text)
{
	if (Text == nullptr)
		return 0;

	std::cout << "\n" << Text;

	return(0);
}

int _STD_CALL CallbackError(const char* Text, int Error)
{
	if (Text == nullptr)
		return 0;

	std::cout << "\n";

#ifdef __LINUX
	std::cout << "\033[31m" << "Error (" << Error << "): "; // highlight error in red color
#else
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
	std::cout << "Error (" << Error << "): ";
#endif // __LINUX
	std::cout << Text;

#ifdef __LINUX
	std::cout << "\033[0m"; // highlight error in red color
#else
	SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN);
#endif // __LINUX

	return 0;
}

int _STD_CALL CallbackProgress(int value, const char* text)
{
	char Line[200];

	sprintf(Line, "\n%d%% %s", value, text);
	std::cout << Line;

	return(0);
}

// Helper functions
void write_ascii(const WinProp_Result* Resultmatrix, const char* Filename) {

	if (Resultmatrix)
	{
		FILE* OutputFile = fopen(Filename, "w");
		if (OutputFile)
		{
			/* Loop through WinPropall pixels. */
			for (int x = 0; x < Resultmatrix->Columns; x++)
			{
				for (int y = 0; y < Resultmatrix->Lines; y++)
				{
					/* Compute real coordinates. */
					double Coordinate_X = Resultmatrix->LowerLeftX + ((double)x + 0.5) * Resultmatrix->Resolution;
					double Coordinate_Y = Resultmatrix->LowerLeftY + ((double)y + 0.5) * Resultmatrix->Resolution;

					/* Check if pixel was computed or not */
					if (Resultmatrix->Matrix[0][x][y] > -1000)
					{
						fprintf(OutputFile, "%.5f\t%.5f\t%.4f\n", Coordinate_X, Coordinate_Y, Resultmatrix->Matrix[0][x][y]);
					}
					else
					{
						fprintf(OutputFile, "%.5f\t%.5f\t%s\n", Coordinate_X, Coordinate_Y, "N.C.");
					}
				}
			}

			/* Close file. */
			fclose(OutputFile);
		}
		else
		{
			printf("\nCould not open the File: %s for writing.\n", Filename);
		}
	}
}

void AntennaPropertiesSet(
	WinProp_Antenna* Antenna,
	double CoordinateX,
	double CoordinateY,
	double Height,
	double Frequency,
	char* Name,
	double Power,
	int PowerMode,
	int Model,
	double Azimuth,
	double Downtilt,
	int Id)
{
	Antenna->Longitude_X = CoordinateX;
	Antenna->Latitude_Y = CoordinateY;
	Antenna->Height = Height;
	Antenna->Power = Power;
	Antenna->PowerMode = PowerMode;
	Antenna->Frequency = Frequency;
	Antenna->Name = Name;
	Antenna->Model = Model;
	Antenna->Azimuth = Azimuth;
	Antenna->Downtilt = Downtilt;
	Antenna->Id = Id;
}

void CarrierPropertiesSet(WinProp_Antenna* Antenna, const WinProp_Carrier* Carrier) {

	Antenna->Carriers.CarrierID = Carrier->CarrierID;
	Antenna->Carriers.SystemID = Carrier->SystemID;
	Antenna->Carriers.CellLoad = Carrier->CellLoad;
	Antenna->Carriers.MimoID = Carrier->MimoID;

	Antenna->Carriers.NoiseRiseUL = Carrier->NoiseRiseUL;
	Antenna->Carriers.PowerBackoffPilotDL = Carrier->PowerBackoffPilotDL;

	// 5G Carrier parameters
	Antenna->Carriers.Numerology = Carrier->Numerology;
	Antenna->Carriers.SymbolsPerSlot = Carrier->SymbolsPerSlot;
	Antenna->Carriers.NrAntennaBeams = Carrier->NrAntennaBeams;
	Antenna->Carriers.BeamGainCtrlServer = Carrier->BeamGainCtrlServer;
	Antenna->Carriers.BeamGainCtrlInterferer = Carrier->BeamGainCtrlInterferer;
	Antenna->Carriers.BeamGainDataServer = Carrier->BeamGainDataServer;
	Antenna->Carriers.BeamGainDataInterferer = Carrier->BeamGainDataInterferer;
	Antenna->Carriers.TDD_Slots_DL = Carrier->TDD_Slots_DL;
	Antenna->Carriers.TDD_Slots_UL = Carrier->TDD_Slots_UL;
	Antenna->Carriers.TDD_Slots_Flex = Carrier->TDD_Slots_Flex;
}