diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.cpp index 53e40ee69..79046a264 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.cpp @@ -274,6 +274,16 @@ void PathLossModel::EstimatePathStateAndVehicleObstacles(AActor *OtherActor, } } +double PathLossModel::CalcVehicleLoss(const double d1, const double d2, const double h) +{ + double V = h * sqrt(2.0 * (d1 + d2) / (lambda * d1 * d2)); + if (V >= -0.78) { + double T = std::pow(V - 0.1, 2) + 1.0; + return 6.9 + 20.0 * log10(sqrt(T + 1.0) + V - 0.1); + } + return 0.0; +} + double PathLossModel::CalculateNLOSvLoss(const FVector Source, const FVector Destination, const double TxHeight, @@ -281,7 +291,6 @@ double PathLossModel::CalculateNLOSvLoss(const FVector Source, const double RxDistance3d, std::vector &vehicle_obstacles) { - double vehicle_blockage_loss = 0.0; // convert all positions to meters FVector pos_tx = Source; @@ -293,21 +302,20 @@ double PathLossModel::CalculateNLOSvLoss(const FVector Source, pos_rx.X /= 100.0f; pos_rx.Y /= 100.0f; pos_rx.Z = RxHeight; - const double distTxRx{sqrt(std::pow(pos_rx.X - pos_tx.X, 2) + std::pow(pos_rx.Y - pos_tx.Y, 2))}; /*< ground distance */ - DiffractionObstacle Tx{0.0, pos_tx.Z}; - DiffractionObstacle Rx{distTxRx, pos_rx.Z}; - auto obsTop = buildTopObstacles(vehicle_obstacles, pos_tx, pos_rx); - - if (!obsTop.empty()) + double max_loss = 0.0; + for(auto veh_it = vehicle_obstacles.begin(); veh_it != vehicle_obstacles.end(); veh_it++) { - obsTop.push_front(Tx); - obsTop.push_back(Rx); - auto path = computeMultipleKnifeEdge(obsTop); - vehicle_blockage_loss = path.attenuation; + double dist_tx_veh = sqrt(std::pow(veh_it->X - pos_tx.X, 2) + std::pow(veh_it->Y - pos_tx.Y, 2)); + double dist_veh_rx = sqrt(std::pow(pos_rx.X - veh_it->X, 2) + std::pow(pos_rx.Y - veh_it->Y, 2)); + double cur_loss = CalcVehicleLoss(dist_tx_veh,dist_veh_rx,veh_it->Z); + if(cur_loss >= max_loss) + { + max_loss = cur_loss; + } } - return vehicle_blockage_loss; + return max_loss; } void PathLossModel::SetPathLossModel(const EPathLossModel path_loss_model) diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.h index 1c43e58bc..2d798995f 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/PathLossModel.h @@ -32,22 +32,6 @@ enum EScenario Urban }; -struct DiffractionObstacle -{ - DiffractionObstacle(double distTx, double height); - // meter - double d; // distance to transmitter - double h; // height of obstacle -}; - -struct DiffractionPath -{ - DiffractionPath(); - - double attenuation; - double d; // meter -}; - class PathLossModel { public: @@ -69,12 +53,8 @@ public: void SetPathLossModel(const EPathLossModel path_loss_model); private: - // multiple knife edge diffraction for NLOSv - double computeVehiclePathLoss(const FVector &pos_tx, const FVector &pos_rx, const double reference_z, std::vector &vehicle_obstacles); - double computeSimpleKnifeEdge(double heightTx, double heightRx, double heightObs, double distTxRx, double distTxObs); - DiffractionPath computeMultipleKnifeEdge(const std::list &obs); - std::list buildTopObstacles(const std::vector &vehicles, const FVector &pos_tx, const FVector &pos_rx); - + // diffraction for NLOSv + double CalcVehicleLoss(const double d1, const double d2, const double h); // powers float CalculateReceivedPower(AActor *OtherActor, const float OtherTransmitPower, diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/VehicleObstacle.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/VehicleObstacle.cpp deleted file mode 100644 index fd27ed80e..000000000 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor/V2X/VehicleObstacle.cpp +++ /dev/null @@ -1,239 +0,0 @@ - -// Copyright (c) 2024 Institut fuer Technik der Informationsverarbeitung (ITIV) at the -// Karlsruhe Institute of Technology -// -// This work is licensed under the terms of the MIT license. -// For a copy, see . - -#pragma once - -#include -#include -#include -#include - -#include "PathLossModel.h" - -namespace -{ - auto compareDistance = [](const DiffractionObstacle &a, const DiffractionObstacle &b) - { return a.d < b.d; }; - auto compareHeight = [](const DiffractionObstacle &a, const DiffractionObstacle &b) - { return a.h < b.h; }; - - using ObstacleIterator = std::list::const_iterator; - ObstacleIterator findMainObstacle(ObstacleIterator, ObstacleIterator); - ObstacleIterator findSecondaryObstacle(ObstacleIterator, ObstacleIterator); -} // namespace - -DiffractionObstacle::DiffractionObstacle(double distTx, double height) : d(distTx), h(height) -{ -} - -DiffractionPath::DiffractionPath() : attenuation(0.0), d(0.0) -{ -} - -double PathLossModel::computeSimpleKnifeEdge(double heightTx, double heightRx, double heightObs, double distTxRx, double distTxObs) -{ - // following calculations are similar to equation 29 of ITU-R P.526-13: - // v = sqrt(2d/lambda * alpha1 * alpha2) - // - // with sinus approximation for small angles: - // alpha1 =~ sin alpha1 = h / d1 - // alpha2 =~ sin alpha2 = h / d2 - // - // v = sqrt(2d / lambda * h / d1 * h / d2) = sqrt(2) * h / sqrt(lambda * d1 * d2 / d) - // - // with d1 = distTxObs, d2 = distRxObs, d = distTxRx, - - // distance between Rx and obstacle - const double distRxObs = distTxRx - distTxObs; - // signed height relative to the line connecting Tx and Rx at obstacle position - const double obsHeightTxRxLine = (heightRx - heightTx) / distTxRx * distTxObs + heightTx; - const double h = heightObs - obsHeightTxRxLine; - // calculate the Fresnel ray - const double r = sqrt(lambda * distTxObs * distRxObs / distTxRx); - static const double root_two = sqrt(2.0); - const double v = root_two * h / r; - - double loss = 0.0; - if (v > -0.78) - { - // approximation of Fresnel-Kirchoff loss given by ITU-R P.526, equation 31 (result in dB): - // J(v) = 6.9 + 20 log(sqrt((v - 01)^2 + 1) + v - 0.1) - loss = 6.9 + 20.0 * log10(sqrt(std::pow(v - 0.1, 2) + 1.0) + v - 0.1); - } - - return loss; -} - -DiffractionPath PathLossModel::computeMultipleKnifeEdge(const std::list &obs) -{ - DiffractionPath path; - - // determine main and secondary obstacles - std::vector mainObs; - mainObs.push_back(obs.begin()); // Tx - for (ObstacleIterator it = obs.begin(); it != obs.end();) - { - it = findMainObstacle(it, obs.end()); - if (it != obs.end()) - { - mainObs.push_back(it); - } - } - // NOTE: Rx is added by loop as last main obstacle - struct SecondaryObstacle - { - SecondaryObstacle(ObstacleIterator tx, ObstacleIterator obs, ObstacleIterator rx) : tx(tx), obstacle(obs), rx(rx) {} - ObstacleIterator tx; - ObstacleIterator obstacle; - ObstacleIterator rx; - }; - - std::vector secObs; - std::vector mainObsDistances; - for (std::size_t i = 0, j = 1; j < mainObs.size(); ++i, ++j) - { - const double d = mainObs[j]->d - mainObs[i]->d; - path.d += sqrt(std::pow(d, 2) + std::pow(mainObs[j]->h - mainObs[i]->h, 2)); - mainObsDistances.push_back(d); - - const auto delta = std::distance(mainObs[i], mainObs[j]); - if (delta == 2) - { - // single other obstacle between two main obstacles - secObs.emplace_back(mainObs[i], std::next(mainObs[i]), mainObs[j]); - } - else if (delta > 2) - { - secObs.emplace_back(mainObs[i], findSecondaryObstacle(mainObs[i], mainObs[j]), mainObs[j]); - } - } - - // attenuation due to main obstacles - double attMainObs = 0.0; - for (std::size_t i = 0; i < mainObs.size() - 2; ++i) - { - const double distTxObs = mainObsDistances[i]; - const double distTxRx = distTxObs + mainObsDistances[i + 1]; - attMainObs += computeSimpleKnifeEdge(mainObs[i]->h, mainObs[i + 2]->h, mainObs[i + 1]->h, distTxRx, distTxObs); - } - - // attenuation due to secondary obstacles - double attSecObs = 0.0; - for (const SecondaryObstacle &sec : secObs) - { - const double distTxRx = sec.rx->d - sec.tx->d; - const double distTxObs = sec.obstacle->d - sec.tx->d; - attSecObs += computeSimpleKnifeEdge(sec.tx->h, sec.rx->h, sec.obstacle->h, distTxRx, distTxObs); - } - - // correction factor C (see eq. 46 in ITU-R P.526-13) - double C = mainObs.back()->d - mainObs.front()->d; // distance between Tx and Rx - for (double d : mainObsDistances) - { - C *= d; - } - double pairwiseDistProduct = 1.0; - for (std::size_t i = 1; i < mainObsDistances.size(); ++i) - { - pairwiseDistProduct *= mainObsDistances[i - 1] + mainObsDistances[i]; - } - C /= mainObsDistances.front() * mainObsDistances.back() * pairwiseDistProduct; - - path.attenuation = attMainObs + attSecObs - 10.0 * log10(C); - return path; -} - -std::list PathLossModel::buildTopObstacles(const std::vector &vehicles, const FVector &pos_tx, const FVector &pos_rx) -{ - std::list diffTop; - const double vx = pos_rx.X - pos_tx.X; - const double vy = pos_rx.Y - pos_tx.Y; - - for (auto vehicle : vehicles) - { - const double midpoint_x = vehicle.X; - const double midpoint_y = vehicle.Y; - const double k = (midpoint_x * vx - vy * pos_tx.Y + vy * midpoint_y - pos_tx.X * vx) / (std::pow(vx, 2) + std::pow(vy, 2)); - if (k < 0.0 || k > 1.0) - continue; /*< skip points beyond the ends of TxRx line segment */ - const double d = k * sqrt(std::pow(vx, 2) + std::pow(vy, 2)); - diffTop.emplace_back(d, vehicle.Z); - } - - diffTop.sort(compareDistance); - return diffTop; -} - -namespace -{ - - ObstacleIterator findMainObstacle(ObstacleIterator begin, ObstacleIterator end) - { - ObstacleIterator mainIterator = end; - double mainAngle = -std::numeric_limits::infinity(); - - if (begin != end) - { - for (ObstacleIterator it = std::next(begin); it != end; ++it) - { - double angle = (it->h - begin->h) / (it->d - begin->d); - if (angle > mainAngle) - { - mainIterator = it; - mainAngle = angle; - } - } - } - - return mainIterator; - } - - ObstacleIterator findSecondaryObstacle(ObstacleIterator first, ObstacleIterator last) - { - ObstacleIterator secIterator = last; - double secHeightGap{std::numeric_limits::infinity()}; - - const double distFirstLast = last->d - first->d; - const double heightFirstLast = last->h - first->h; - const auto offset = first->h * last->d - first->d * last->h; - for (ObstacleIterator it = std::next(first); it != last; ++it) - { - const double heightGap = ((it->d * heightFirstLast + offset) / distFirstLast) - it->h; - if (heightGap < secHeightGap) - { - secIterator = it; - secHeightGap = heightGap; - } - } - - return secIterator; - } - -} // namespace - -// statistical model from ETSI TR 103 257-1 V1.1.1 (2019-05) -double PathLossModel::MakeVehicleBlockageLoss(double TxHeight, double RxHeight, double obj_height, double obj_distance) -{ - // according to ETSI, stochastic method - if (TxHeight > obj_height && RxHeight > obj_height) - { - // no blocking if higher than obj - return 0.0; - } - else if (TxHeight < obj_height && RxHeight < obj_height) - { - // worst case: obj is higher than both tx and rx - float mean = 9.0f + fmax(0.0f, 15.0f * log10(obj_distance) - 41.0f); - return mRandomEngine->GetNormalDistribution(mean, 4.5f); - } - else - { - // something in between - float mean = 5.0f + fmax(0.0f, 15.0f * log10(obj_distance) - 41.0f); - return mRandomEngine->GetNormalDistribution(mean, 4.0f); - } -}