Mobile Station Post-processing (RunMS) in Urban Scenarios

Detailed Description

This is an example of how to carry out mobile station post-processing, with the WinProp API, in an urban scenario. The full example is distributed with the installation.
#include <stdio.h>
#include <string>
#include <iostream>

#include "outdoor_propagation_runms.h"

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

int main(int argc, char** argv)
{
	int                 Error = 0;
	WinProp_ParaMain    GeneralParameters;
	WinProp_Antenna     Antenna;
	WinProp_Callback    Callback;
	WinProp_ResultTrajectoryList WinPropResultTrajectories;
	WinProp_Propagation_Results OutputResults;

	// Set up input trajectory
	int NrWinPropTrajectories = 1;
	WinProp_Trajectory* WinPropTrajectories = nullptr;
	WinPropTrajectories = (WinProp_Trajectory*)malloc(sizeof(WinProp_Trajectory) * NrWinPropTrajectories);
	if (WinPropTrajectories != nullptr)
	{
		WinProp_Structure_Init_Trajectory(&WinPropTrajectories[0]);
		WinPropTrajectories[0].Id = 1;
		WinPropTrajectories[0].PointSize = 5.0;
		WinPropTrajectories[0].samplingResolution = 1.0;
		WinPropTrajectories[0].NrPoints = 9;
		WinPropTrajectories[0].Points = (WinProp_Trajectory_Point*)malloc(sizeof(WinProp_Trajectory_Point) * WinPropTrajectories[0].NrPoints);
		if (WinPropTrajectories[0].Points != nullptr)
		{
			for (int i = 0; i < WinPropTrajectories[0].NrPoints; i++)
				WinProp_Structure_Init_TrajectoryPoint(&WinPropTrajectories[0].Points[i]);

			WinPropTrajectories[0].Points[0].location.x = 476101.49;
			WinPropTrajectories[0].Points[0].location.y = 552413.58;
			WinPropTrajectories[0].Points[0].location.z = 1.5;

			WinPropTrajectories[0].Points[1].location.x = 476597.37;
			WinPropTrajectories[0].Points[1].location.y = 552604.19;
			WinPropTrajectories[0].Points[1].location.z = 1.5;

			WinPropTrajectories[0].Points[2].location.x = 476607.80;
			WinPropTrajectories[0].Points[2].location.y = 552620.57;
			WinPropTrajectories[0].Points[2].location.z = 1.5;

			WinPropTrajectories[0].Points[3].location.x = 476391.13;
			WinPropTrajectories[0].Points[3].location.y = 553024.13;
			WinPropTrajectories[0].Points[3].location.z = 1.5;

			WinPropTrajectories[0].Points[4].location.x = 476333.05;
			WinPropTrajectories[0].Points[4].location.y = 553030.83;
			WinPropTrajectories[0].Points[4].location.z = 1.5;

			WinPropTrajectories[0].Points[5].location.x = 476201.26;
			WinPropTrajectories[0].Points[5].location.y = 552888.62;
			WinPropTrajectories[0].Points[5].location.z = 1.5;

			WinPropTrajectories[0].Points[6].location.x = 475830.47;
			WinPropTrajectories[0].Points[6].location.y = 552670.46;
			WinPropTrajectories[0].Points[6].location.z = 1.5;

			WinPropTrajectories[0].Points[7].location.x = 475810.36;
			WinPropTrajectories[0].Points[7].location.y = 552624.29;
			WinPropTrajectories[0].Points[7].location.z = 1.5;

			WinPropTrajectories[0].Points[8].location.x = 476082.88;
			WinPropTrajectories[0].Points[8].location.y = 552423.26;
			WinPropTrajectories[0].Points[8].location.z = 1.5;
		}
	}

	// name of .odb database without extension
	const char* my_odb_database = API_DATA_FOLDER "outdoor/Frankfurt";

	/* ------------------------ Initialisation of parameters ----------------------*/
	WinProp_Structure_Init_ParameterMain(&GeneralParameters);
    WinProp_Structure_Init_Antenna(&Antenna);
    WinProp_Structure_Init_Callback(&Callback);
	WinProp_Structure_Init_ResultTrajectoryList(&WinPropResultTrajectories);
	WinProp_Structure_Init_Propagation_Results(&OutputResults);

	/*---------------- Definition of scenario -------------------------------------*/
	/* Definition of general parameters. */
	GeneralParameters.ScenarioMode = SCENARIOMODE_URBAN; // Urban prediction
	GeneralParameters.PredictionModelUrban = PREDMODEL_UDP; // Use Dominant Path Model

	/* Definition of prediction trajectory. */
	GeneralParameters.UrbanLowerLeftX = 475800.0;
	GeneralParameters.UrbanLowerLeftY = 552400.0;
	GeneralParameters.UrbanUpperRightX = 476620.0;
	GeneralParameters.UrbanUpperRightY = 553040.0;

	/* 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;

	double PredictionHeight = 1.5;

	/* Size of matrix with results. */
	GeneralParameters.Resolution = 5.0;                      // Resolution in meter
	GeneralParameters.NrLayers = 1;                          // Number of prediction heights
	GeneralParameters.PredictionHeights = &PredictionHeight; // Prediction height in meter

	/* Building vector data and topography. */
	GeneralParameters.BuildingsMode = BUILDINGSMODE_BINARY; // load a .opb database (urban)
	sprintf(GeneralParameters.BuildingsName, "%s", my_odb_database); // Vector database in WinProp format

	/*--------------------------- Definition of antenna ---------------------------*/
	/* Position and configuration. */
	Antenna.Id = 1;
	Antenna.SiteId = 1;
	Antenna.Longitude_X = 476079.78;
	Antenna.Latitude_Y = 552495.05;
	Antenna.Height = 25.0;
	Antenna.Power = 40.0; // Power in dBm
    Antenna.Frequency = 2000.0; // Frequency in MHz
    char AntennaName[500];
    sprintf(AntennaName, "%s", "Antenna 1");
    Antenna.Name = AntennaName;

	/* Definition of outputs to be computed and written in WinProp format. */
	GeneralParameters.OutputResults = &OutputResults;
	OutputResults.ResultPath = API_DATA_FOLDER "output/OutdoorRunPRO"; // Output data directory 
	OutputResults.FieldStrength = 1;
	OutputResults.PathLoss = 1;
	OutputResults.StatusLOS = 1;
	OutputResults.RayFilePropPaths = 1;
	OutputResults.StrFilePropPaths = 1;

	/*-------------------------- Callbacks ----------------------------------------*/
	Callback.Percentage = CallbackProgress;
	Callback.Message = CallbackMessage;
	Callback.Error = CallbackError;

	/*----------------------- Compute outdoor prediction --------------------------*/
	Error = OutdoorPlugIn_ComputeTrajectories(
		&Antenna, &GeneralParameters, NULL, NULL,
		WinPropTrajectories, NrWinPropTrajectories, &Callback, &WinPropResultTrajectories);
	
	/*----------------------- Do something with results ---------------------------*/
	if (Error == 0)
	{
		write_ascii(&WinPropResultTrajectories, API_DATA_FOLDER "output/OutdoorRunPRO.txt");
	}
	else {
		/* Error during prediction. Print error message. */
		CallbackError(GeneralParameters.ErrorMessageMain, Error);
	}

	/*----------------------- Rx antenna superposition (RunMS) --------------------*/
	// Create project
	WinProp_SuperposeMS superposeMS;

	/* Definition of antenna pattern. */
	WinProp_Pattern     WinPropPattern;
	WinProp_Structure_Init_Pattern(&WinPropPattern);
	WinPropPattern.Mode = PATTERN_MODE_FILE; // Load pattern from file
	char PatternFileName[500];
	sprintf(PatternFileName, "%s", API_DATA_FOLDER "antennas/Antenna.apb"); // Pattern file (including extension)
	WinPropPattern.Filename = PatternFileName;

	// Setup tx array
	WINPROP_MS_ARRAY_TYPE txArrayAPI = WINPROP_MS_ARRAY_SINGLE_ANTENNA;
	WINPROP_MS_POLARIZATION_TYPE pol = WINPROP_MS_POLARIZATION_VERTICAL;
	if (Error == 0)
		Error = superposeMS.setArray(false, txArrayAPI, 1, 0.f, 0.f, 0.f, 0);
	if (Error == 0)
		// Changing the azimuth from north over east in RunPRO to east over north orientation, 90deg
		// tilt is equal to horizontal orientation.
		Error = superposeMS.setArrayElement(
			false, 0, nullptr, nullptr,
			(float)(-Antenna.Azimuth + 90. + 360.),
			(float)(Antenna.Downtilt + 90.), pol, { 0., 0., 0. });

	// Setup rx array
	WINPROP_MS_ARRAY_TYPE rxArrayAPI = WINPROP_MS_ARRAY_SINGLE_ANTENNA;
	if (Error == 0)
		Error = superposeMS.setArray(true, rxArrayAPI,
			1   /*rxArray.nbrElements*/,
			0.f /*rxArray.arrayAzimuth*/,
			0.f /*rxArray.spacingHorizontal*/,
			0.f /*rxArray.radius*/,
			false /*rxArray.antCoupling != 0*/);

	if (Error == 0)
		// azimuth with east over north orientation, in case of trajectories 0deg means 90deg right
		// from driving direction, using 180deg here to point the Rx antenna towards the Tx 90deg tilt
		// is equal to horizontal orientation.
		Error = superposeMS.setArrayElement(
			true, 0, &WinPropPattern, nullptr,
			180.f/*azimuth*/, 90.f/*tilt*/,
			pol, { 0., 0., 0. }/*offset*/);

	if (Error == 0)
		Error = superposeMS.setPropagationTrajectories(
			0, Antenna, WinPropTrajectories, NrWinPropTrajectories, WinPropResultTrajectories);


	// Set computation parameter 
	WinProp_MS_Para msPara;
	WinProp_Structure_Init_MS_Para(&msPara);
	// Enable ouputs
	WinProp_MS_AdditionalResults msAdditionalResult;
	WinProp_Structure_Init_MS_AdditionalResults(&msAdditionalResult);
	sprintf(msAdditionalResult.outputPath, "%s%s", API_DATA_FOLDER, "output/OutdoorRunMS");

	if (Error == 0)
		Error = superposeMS.compute(msPara, &msAdditionalResult, &Callback);

	/*----------------------------- Free memory -----------------------------------*/
	WinProp_Structure_Free_ResultTrajectoryList(&WinPropResultTrajectories);
	if (WinPropTrajectories != nullptr)
	{
		if (WinPropTrajectories->Points != nullptr)
			free(WinPropTrajectories->Points);
		free(WinPropTrajectories);
	}


	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);
}

void write_ascii(const WinProp_ResultTrajectoryList* Result, const char* Filename) {
	FILE* OutputFile = fopen(Filename, "w");
	if (OutputFile)
	{
		/* Loop all pixels. */
		for (int x = 0; x < Result->NrTrajectories; x++)
		{
			for (int y = 0; y < Result->trajectories[x].ResultPoints.NrResultPoints; y++)
			{
				/* Compute real coordinates. */
				double Coordinate_X = Result->trajectories[x].ResultPoints.ResultPoints[y].Location.x;
				double Coordinate_Y = Result->trajectories[x].ResultPoints.ResultPoints[y].Location.y;
				double Coordinate_Z = Result->trajectories[x].ResultPoints.ResultPoints[y].Location.z;
				double ResultValue = Result->trajectories[x].ResultPoints.ResultPoints[y].ResultValue;

				/* Check if pixel was computed or not */
				if (ResultValue > -1000)
					fprintf(OutputFile, "%.2f\t%.2f\t%.2f\t%.2f\n", Coordinate_X, Coordinate_Y, Coordinate_Z, ResultValue);
			}
		}

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