FMCW Radar Postprocessing in Time-variant Indoor Scenarios
Detailed Description
This is an example of how to use the WInProp API for FMCW radar postprocessing in a time-variant indoor scenario. The full example is distributed with the installation.#include <cstdio> #include <string> #include <iostream> #include "indoor_propagation_fmcw.h" #include "../SuperposeMS/winprop_superposems.hpp" #include "../SuperposeMS/winprop_superposems_engine.h" #include "../Interface/Init.h" #include "../FMCW/winprop_fmcw_radar.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; /* ------------------ Initialization of scenario --------------------------- */ WinProp_Scenario WinPropScenario; WinProp_Structure_Init_Scenario(&WinPropScenario); /* ---------- Load indoor vector database and initialize scenario ------------ */ /* Assign database name. */ WinPropScenario.Scenario = WINPROP_SCENARIO_INDOOR; sprintf(WinPropScenario.VectorDatabase, "%s", API_DATA_FOLDER "../data/indoor/RadarScenario.idb"); /* Define callback functions. */ WinProp_Callback WinPropCallback; WinProp_Structure_Init_Callback(&WinPropCallback); WinPropCallback.Percentage = CallbackProgress; WinPropCallback.Message = CallbackMessage; WinPropCallback.Error = CallbackError; /* ------------------------- Set up prediction ------------------------------- */ if (Error == 0) { /* Definition of prediction points. */ int NrPoints = 1; WinProp_Receiver WinPropReceiver; WinProp_Structure_Init_Receiver(&WinPropReceiver); WinPropReceiver.Location.x = 5.8; WinPropReceiver.Location.y = -2.; WinPropReceiver.Location.z = 0.5; WinPropReceiver.GroupID = 230; // Group id of the radar car /* Definition of antenna pattern. */ WinProp_Pattern WinPropPattern; WinProp_Structure_Init_Pattern(&WinPropPattern); WinPropPattern.Mode = PATTERN_MODE_FILE; // Load pattern from file sprintf(WinPropPattern.Filename, "%s", API_DATA_FOLDER "antennas/RadarAntenna.ffe");// Pattern file (including extension) /* Definition of antenna properties. */ WinProp_Antenna WinPropAntenna; WinProp_Structure_Init_Antenna(&WinPropAntenna); WinPropAntenna.Enabled = 1; WinPropAntenna.Id = 1; WinPropAntenna.SiteId = 1; WinPropAntenna.Longitude_X = 5.8; WinPropAntenna.Latitude_Y = -2.0; WinPropAntenna.Height = 0.5; // Antenna height 0.5 meter WinPropAntenna.Model = WINPROP_MODEL_SRT; // Use the standard ray tracing WinPropAntenna.DataType = PROP_RESULT_POWER; // Compute received power WinPropAntenna.Power = 13.; // Power in dBm WinPropAntenna.PowerMode = WINPROP_POWER_OUTPUT; // Power mode WinPropAntenna.Frequency = 77000.; // Frequency 77 GHz WinPropAntenna.Pattern = &WinPropPattern; // Use pattern defined above WinPropAntenna.Azimuth = 90.; // Antenna points in eastern direction WinPropAntenna.Downtilt = 0.; // Downtilt of 0 degree WinPropAntenna.GroupIDMounted = 230; // Group id of the radar car sprintf(WinPropAntenna.Name, "%s", "radar_antenna"); // name of the antenna /* Definition of ray tracing parameters. */ Model_RAYTRACING ModelRT; WinProp_Structure_Init_Model_RayTracing(&ModelRT); ModelRT.MaxNrDiffractions = 1; ModelRT.MaxNrReflections = 1; ModelRT.MaxNrTransmissions = 0; ModelRT.MaxNrReflDiffr = 1; ModelRT.Superposition = 1; ModelRT.ComputeAlwaysDirectRay = 2; /* Definition of outputs to be computed and written in WinProp format. */ WinProp_Additional WinPropMore; WinProp_Propagation_Results OutputResults; WinProp_Structure_Init_Additional(&WinPropMore); WinProp_Structure_Init_Propagation_Results(&OutputResults); WinPropMore.OutputResults = &OutputResults; OutputResults.RayFilePropPaths = 1; OutputResults.StrFilePropPaths = 1; /* Further parameters: */ WinPropMore.InteractionModel = WINPROP_INTERACTION_MODEL_GTDUTD; WinPropMore.MaxNumberPathsUsed = 1; WinPropMore.MaxNumberPaths = 64; WinPropMore.MaxDynamicPathsEnabled = 1; WinPropMore.MaxDynamicPaths = 100.; WinPropMore.MaxPathLossEnabled = 1; WinPropMore.MaxPathLoss = 200.; /* Set time instance(s) and output folder */ double timeInstances[1] = { 1.0 }; // 1 s WinPropMore.TimeInstances = timeInstances; WinPropMore.NbrTimeInstances = 1; sprintf(OutputResults.ResultPath, "%s", API_DATA_FOLDER "output/prop"); // name of the antenna /* Call the WinProp API to open a project and load the vector database. */ int ProjectHandle = 0; Error = WinProp_Open(&ProjectHandle, &WinPropScenario, &WinPropCallback); /* ----- Start prediction (including loop over all time instances) ------ */ WinProp_ResultPointsList* PowerResult = nullptr; Error = WinProp_Predict_Points( ProjectHandle, &WinPropAntenna, &WinPropReceiver, NrPoints, &ModelRT, &WinPropMore, &PowerResult, nullptr, nullptr); // Optionally, create range-angle heat maps bool generateRangeAngle = true; int nbrRxElements = 16; // nr of RX elements in a linear array, relevant for range-angle heat maps float rxSpacing = 0.5; // elments spacing in [lambda], relevant for range-angle heat maps WinProp_RayMatrixElement subStreamRays[16]; // ray matices for sub-stream results, relevant for range-angle heat maps for (int i = 0; i < nbrRxElements; i++) WinProp_Structure_Init_RayMatrixElement(&subStreamRays[i]); if (generateRangeAngle) { /*----------------------- Rx antenna superposition (RunMS) --------------------*/ // Create project WinProp_SuperposeMS SuperposeMS; // 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, false); 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)(-WinPropAntenna.Azimuth + 90. + 360.), (float)(WinPropAntenna.Downtilt + 90.), pol, { 0., 0., 0. }); // Setup rx array WINPROP_MS_ARRAY_TYPE rxArrayAPI = WINPROP_MS_ARRAY_LINEAR; if (Error == 0) { Error = SuperposeMS.setArray(true, rxArrayAPI, /* array Type*/ nbrRxElements /* nrElements */, 270.f /* array azimuth */, rxSpacing /*rx spacing */, 0.f /* radius*/, false /* considerAntennaCoupling */); } // set individual rx elements for (int rx = 0; rx < nbrRxElements && Error == 0; rx++) { // element azimuth with east over north orientation (overall direction: east when adding array Azimuth), // 90deg tilt is equal to horizontal orientation. Error = SuperposeMS.setArrayElement( true, rx, &WinPropPattern, nullptr, 90.f/*azimuth*/, 90.f/*tilt*/, pol, { 0., 0., 0. }/*offset*/); } // Set computation parameter WinProp_MS_Para msPara; WinProp_Structure_Init_MS_Para(&msPara); msPara.coherentSuperposition = 1; msPara.nrRays = 64; // Enable ouputs WinProp_MS_AdditionalResults msAdditionalResult; WinProp_Structure_Init_MS_AdditionalResults(&msAdditionalResult); msAdditionalResult.propagationPaths = 1; msAdditionalResult.perSubChannelPower = 1; sprintf(msAdditionalResult.outputPath, "%s%s", API_DATA_FOLDER, "output/runMS"); // set propagtion points if (Error == 0) Error = SuperposeMS.setPropagationPoints(0, WinPropAntenna, *PowerResult); // compute RunMS if (Error == 0) Error = SuperposeMS.compute(msPara, &msAdditionalResult, &WinPropCallback); // get sub-stream results for (int rx = 0; rx < nbrRxElements && Error == 0; rx++) { WinProp_ResultPointsList subStreamRes; WinProp_Structure_Init_ResultPointsList(&subStreamRes); char subStreamResPower[1024]; char subStreamResRays[1024]; sprintf(subStreamResPower, "%s/%s Sub-Channel Rx-%d Power.fpp", msAdditionalResult.outputPath, WinPropAntenna.Name, rx + 1); sprintf(subStreamResRays, "%s/%s Sub-Channel Rx-%d Rays.ray", msAdditionalResult.outputPath, WinPropAntenna.Name, rx + 1); Error = WinProp_ResultPoints_Read(&subStreamRes, subStreamResPower, subStreamResRays); if (Error == 0) { // move rays subStreamRays[rx] = subStreamRes.ResultPoints[0].Rays; subStreamRes.ResultPoints[0].Rays.NrRays = 0; subStreamRes.ResultPoints[0].Rays.Rays = nullptr; } WinProp_Structure_Free_ResultPointsList(&subStreamRes); } } if (Error == 0) { /* ------------------------- FMCW radar ------------------------------- */ /* Definition of radar parameters */ WinProp_FMCW_Para RadarPara; RadarPara.Mode = WinProp_FMCW_Para::ParametersMode::SET_PARAMETERS; // set parameters mode RadarPara.Freq = 77e9; // radar frequency RadarPara.Tc = 20e-6; // chirp duration RadarPara.B = 1e9; // sweep bandwidth RadarPara.NrChirps = 64; // number of chirps RadarPara.Cohrent = true; // coherent superposition of rays RadarPara.NrBins = WinProp_FMCW_Para::FreqBins::FFT_512; // FFT Samples (range domain) RadarPara.NrRx = generateRangeAngle ? nbrRxElements : 1; RadarPara.RxSpacing = rxSpacing * 2.99792458e8 / (WinPropAntenna.Frequency * 1.e6); /* Parameters relevant to output results */ RadarPara.WindFunc = WinProp_FMCW_Para::Windowing::HANNING; RadarPara.GenerateRangeDoppler = true; RadarPara.GenerateRangeAngle = generateRangeAngle; RadarPara.GenerteIQ = false; /* Range-Doppler heatmap result */ WinProp_ResultPlane RangeVelocity; WinProp_Structure_Init_ResultPlane(&RangeVelocity); /* Range-Angle heatmap result */ WinProp_ResultPlane RangeAngle; WinProp_Structure_Init_ResultPlane(&RangeAngle); /*------- FMCW radar post-processing -------*/ WinProp_FMCW_Radar FMCW_Radar; Error = FMCW_Radar.compute(&RadarPara, RadarPara.NrRx, generateRangeAngle ? subStreamRays : &PowerResult->ResultPoints[0].Rays, &WinPropCallback, &RangeVelocity, generateRangeAngle ? &RangeAngle : nullptr); /* Use RangeVelocity to find the range and velocity of the targets */ if (Error == 0 && RadarPara.GenerateRangeDoppler) { /* Save values in ASCII file */ const char* Filename = API_DATA_FOLDER "output/rangeDopplerHeatmap.txt"; FILE* OutputFile = fopen(Filename, "w"); for (int i = 0; i < RangeVelocity.Columns; i++) { for (int j = 0; j < RangeVelocity.Lines; j++) { fprintf(OutputFile, "%.3f\t%.3f\t%.3f\n", RangeVelocity.Matrix[i][j].Location.x, RangeVelocity.Matrix[i][j].Location.y, RangeVelocity.Matrix[i][j].Value); } } /* Close file. */ fclose(OutputFile); } if (Error == 0 && RadarPara.GenerateRangeAngle) { /* Save values in ASCII file */ const char* Filename = API_DATA_FOLDER "output/rangeAngleHeatmap.txt"; FILE* OutputFile = fopen(Filename, "w"); for (int i = 0; i < RangeAngle.Columns; i++) { for (int j = 0; j < RangeAngle.Lines; j++) { fprintf(OutputFile, "%.3f\t%.3f\t%.3f\n", RangeAngle.Matrix[i][j].Location.x, RangeAngle.Matrix[i][j].Location.y, RangeAngle.Matrix[i][j].Value); } } /* Close file. */ fclose(OutputFile); } /* Free memory */ WinProp_Structure_Free_ResultPlane(&RangeVelocity); WinProp_Structure_Free_ResultPlane(&RangeAngle); } /* Free memory */ WinProp_Structure_Free_ResultPointsList(PowerResult); for (int i = 0; i < nbrRxElements; i++) WinProp_FreeRayMatrixElement(&subStreamRays[i]); /* Close project */ WinProp_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); }