CARLA
 
载入中...
搜索中...
未找到
PathLossModel.cpp
浏览该文件的文档.
1// Copyright (c) 2024 Institut fuer Technik der Informationsverarbeitung (ITIV) at the
2// Karlsruhe Institute of Technology
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "Carla.h"
9#include "Math/UnrealMathUtility.h"
10
11#include "PathLossModel.h"
12#include <random>
13#include <limits>
14
16double PathLossModel::Frequency = 5.9f * std::pow(10, 9);
17double PathLossModel::lambda = PathLossModel::c_speedoflight / (5.9f * std::pow(10, 9));
18
20{
21 mRandomEngine = random_engine;
22}
23
25{
26 mActorOwner = Owner;
27}
28
29void PathLossModel::SetParams(const float TransmitPower,
30 const float ReceiverSensitivity,
31 const float Frequency,
32 const float combined_antenna_gain,
33 const float path_loss_exponent,
34 const float reference_distance_fspl,
35 const float filter_distance,
36 const bool use_etsi_fading,
37 const float custom_fading_stddev)
38{
39 this->TransmitPower = TransmitPower;
40 this->ReceiverSensitivity = ReceiverSensitivity;
41 this->path_loss_exponent = path_loss_exponent;
42 this->reference_distance_fspl = reference_distance_fspl;
43 this->filter_distance = filter_distance;
44 this->use_etsi_fading = use_etsi_fading;
45 this->custom_fading_stddev = custom_fading_stddev;
46 this->combined_antenna_gain = combined_antenna_gain;
50 // when reference distance is set, we prepare the FSPL for the reference distance to be used in LDPL
52}
53
55{
56 this->scenario = scenario;
57}
58
59std::map<AActor *, float> PathLossModel::GetReceiveActorPowerList()
60{
62}
63
64void PathLossModel::Simulate(const std::vector<ActorPowerPair> ActorList, UCarlaEpisode *CarlaEpisode, UWorld *World)
65{
66 // Set current world and episode
67 mWorld = World;
68 mCarlaEpisode = CarlaEpisode;
69
70 CurrentActorLocation = mActorOwner->GetTransform().GetLocation();
71 FVector OtherActorLocation;
73 float ReceivedPower = 0;
74 // Logic to get height of the vehicle
75 // TODO: make that thing use the actual attachment and transform of the sensor
76
77 double tx_height_local = (mActorOwner->GetSimpleCollisionHalfHeight() * 2.0f) + 2.0;
78
80
81 for (auto &actor_power_pair : ActorList)
82 {
83 const FCarlaActor *view = Registry.FindCarlaActor(actor_power_pair.first);
84 // ensure other actor is still alive
85 if (!view)
86 {
87 continue;
88 }
89 OtherActorLocation = actor_power_pair.first->GetTransform().GetLocation();
90 double rx_height_local = (actor_power_pair.first->GetSimpleCollisionHalfHeight() * 2.0) + 2.0;
91
92 // calculate relative ht and hr respecting slope and elevation
93 // cm
94 // if objects are on a slope, minimum Z height of both is the reference to calculate transmitter height
95 double ref0 = std::min(CurrentActorLocation.Z, OtherActorLocation.Z);
96 // cm
97 double ht = CurrentActorLocation.Z + tx_height_local - ref0;
98 double hr = OtherActorLocation.Z + rx_height_local - ref0;
99 // localize to common ref0 as ground
100 FVector source_rel = CurrentActorLocation;
101 source_rel.Z += tx_height_local;
102 FVector dest_rel = OtherActorLocation;
103 dest_rel.Z += rx_height_local;
104
105 double Distance3d = FVector::Distance(source_rel, dest_rel) / 100.0f; // From cm to m
106 // to meters
107 ht = ht / 100.0f;
108 hr = hr / 100.0f;
109
110 if (Distance3d < filter_distance) // maybe change this for highway
111 {
112 float OtherTransmitPower = actor_power_pair.second;
113 ReceivedPower = CalculateReceivedPower(actor_power_pair.first,
114 OtherTransmitPower,
116 OtherActorLocation,
117 Distance3d,
118 ht,
119 tx_height_local,
120 hr,
121 rx_height_local,
122 ref0);
123 if (ReceivedPower > -1.0 * std::numeric_limits<float>::max())
124 {
125 mReceiveActorPowerList.insert(std::make_pair(actor_power_pair.first, ReceivedPower));
126 }
127 }
128 }
129}
130
132 const float OtherTransmitPower,
133 const FVector Source,
134 const FVector Destination,
135 const double Distance3d,
136 const double ht,
137 const double ht_local,
138 const double hr,
139 const double hr_local,
140 const double reference_z)
141{
142 // hr in m
143 // ht in m
144 // reference_z in cm
145 // distance3d in m
146 bool ret = false;
147 FCollisionObjectQueryParams ObjectParams;
148 // Channels to check for collision with different object types
149 ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_WorldStatic);
150 ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_PhysicsBody);
151 ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_Vehicle);
152 ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_WorldDynamic);
153 HitResult.Reset();
154
155 FVector tx = Source;
156 tx.Z += ht_local;
157 FVector rx = Destination;
158 rx.Z += hr_local;
159 mWorld->LineTraceMultiByObjectType(HitResult, tx, rx, ObjectParams);
160
161 // all losses
162 float loss = ComputeLoss(OtherActor, Source, Destination, Distance3d, ht, hr, reference_z);
163
164 // we incorporate the tx power of the sender (the other actor), not our own
165 // NOTE: combined antenna gain is parametrized for each sensor. Better solution would be to parametrize individual antenna gain
166 // and combine at the receiver. This would allow to better account for antenna characteristics.
167 float ReceivedPower = OtherTransmitPower + combined_antenna_gain - loss;
168
169 if (ReceivedPower >= ReceiverSensitivity)
170 {
171 ret = true;
172 }
173 float deltaPercentage = loss / (OtherTransmitPower - ReceiverSensitivity);
174
175 // Works only when run in debug mode
176 DrawDebugLine(
177 mWorld,
178 tx,
179 rx,
180 FColor::Cyan,
181 false, 0.05f, 0,
182 30);
183 if (deltaPercentage < 0.65)
184 {
185 DrawDebugLine(
186 mWorld,
187 tx,
188 rx,
189 FColor::Green,
190 false, 0.1f, 0,
191 30);
192 }
193 else if (deltaPercentage < 0.8)
194 {
195 DrawDebugLine(
196 mWorld,
197 tx,
198 rx,
199 FColor::Orange,
200 false, 0.1f, 0,
201 30);
202 }
203 else if (ReceivedPower >= ReceiverSensitivity)
204 {
205 DrawDebugLine(
206 mWorld,
207 tx,
208 rx,
209 FColor::Red,
210 false, 0.1f, 0,
211 30);
212 }
213
214 if (ret)
215 {
216 return ReceivedPower;
217 }
218 else
219 {
220 return -1.0 * std::numeric_limits<float>::max();
221 }
222}
223
225 FVector CurrentActorLocation,
226 double TxHeight,
227 double RxHeight,
228 double reference_z,
229 EPathState &state,
230 std::vector<FVector> &vehicle_obstacles)
231{
232 // CurrentActorLocation in cm original
233 // TxHeight in m
234 // RxHeight in m
235 // reference_z in cm
236
237 // init with LOS
238 state = EPathState::LOS;
239 if (HitResult.Num() == 0)
240 {
241 // no hits --> LOS
242 return;
243 }
244
245 // check all hits
246 for (const FHitResult &HitInfo : HitResult)
247 {
248
249 FVector location;
250 if (HitIsSelfOrOther(HitInfo, OtherActor))
251 {
252 // the current hit is either Tx or Rx, so we can skip it, no obstacle
253 continue;
254 }
255
256 // cal by ref
257 if (GetLocationIfVehicle(CurrentActorLocation, HitInfo, reference_z, location))
258 {
259 // we found a vehicle
260 // Note: we may set this several times if we have several vehicles in between
261 state = EPathState::NLOSv;
262 // z (height) is gonna be in m in relation to reference height
263 // x,y also in meters
264 // call by reference
265 vehicle_obstacles.emplace_back(location);
266
267 // alternative (cf Etsi): statistical model
268 // vehicle_blockage_loss += MakeVehicleBlockageLoss(TxHeight, RxHeight, obj_height, obj_dist);
269 }
270 // but if we hit a building, we stop and switch to NLOSb
271 else
272 {
273 state = EPathState::NLOSb;
274 break;
275 }
276 }
277}
278
279double PathLossModel::CalcVehicleLoss(const double d1, const double d2, const double h)
280{
281 double V = h * sqrt(2.0 * (d1 + d2) / (lambda * d1 * d2));
282 if (V >= -0.78) {
283 double T = std::pow(V - 0.1, 2);
284 return 6.9 + 20.0 * log10(sqrt(T + 1.0) + V - 0.1);
285 }
286 return 0.0;
287}
288
289double PathLossModel::CalculateNLOSvLoss(const FVector Source,
290 const FVector Destination,
291 const double TxHeight,
292 const double RxHeight,
293 const double RxDistance3d,
294 std::vector<FVector> &vehicle_obstacles)
295{
296
297 // convert all positions to meters
298 FVector pos_tx = Source;
299 pos_tx.X /= 100.0f;
300 pos_tx.Y /= 100.0f;
301 pos_tx.Z = TxHeight;
302
303 FVector pos_rx = Destination;
304 pos_rx.X /= 100.0f;
305 pos_rx.Y /= 100.0f;
306 pos_rx.Z = RxHeight;
307
308 double max_loss = 0.0;
309 for(auto veh_it = vehicle_obstacles.begin(); veh_it != vehicle_obstacles.end(); veh_it++)
310 {
311 double dist_tx_veh = sqrt(std::pow(veh_it->X - pos_tx.X, 2) + std::pow(veh_it->Y - pos_tx.Y, 2));
312 double dist_veh_rx = sqrt(std::pow(pos_rx.X - veh_it->X, 2) + std::pow(pos_rx.Y - veh_it->Y, 2));
313 double cur_loss = CalcVehicleLoss(dist_tx_veh,dist_veh_rx,veh_it->Z);
314 if(cur_loss >= max_loss)
315 {
316 max_loss = cur_loss;
317 }
318 }
319
320 return max_loss;
321}
322
324{
325 model = path_loss_model;
326}
327
328float PathLossModel::ComputeLoss(AActor *OtherActor, FVector Source, FVector Destination, double Distance3d, double TxHeight, double RxHeight, double reference_z)
329{
330 // TxHeight in m
331 // RxHeight in m
332 // reference_z in cm
333 // distance3d in m
334 EPathState state;
335
336 float PathLoss = 0.0;
337 double VehicleBlockageLoss = 0.0;
338 float ShadowFadingLoss = 0.0;
339
340 // state and vehicle obstacles are call-by-reference
341 std::vector<FVector> vehicle_obstacles;
342 EstimatePathStateAndVehicleObstacles(OtherActor, Source, TxHeight, RxHeight, reference_z, state, vehicle_obstacles);
343
345 {
346 // calculate pure path loss depending on state and scenario
347 PathLoss = CalculatePathLoss_WINNER(state, Distance3d);
348 // in nlosv case, add multi knife edge
349 if (state == EPathState::NLOSv)
350 {
351 PathLoss = PathLoss + CalculateNLOSvLoss(Source, Destination, TxHeight, RxHeight, Distance3d, vehicle_obstacles);
352 }
353 }
354 else
355 {
356 if (state == EPathState::LOS)
357 {
358 // full two ray path loss
359 PathLoss = CalculateTwoRayPathLoss(Distance3d, TxHeight, RxHeight);
360 }
361 else if (state == EPathState::NLOSb)
362 {
363 // log distance path loss
364 PathLoss = (m_fspl_d0 + 10.0 * path_loss_exponent * log10(Distance3d / reference_distance_fspl));
365 }
366 else
367 {
368 // fspl + knife edge
369 // fspl
370 double free_space_loss = 20.0 * log10(Distance3d) + 20.0 * log10(4.0 * PI / lambda);
371 // add the knife edge vehicle blockage loss
372 PathLoss = free_space_loss + CalculateNLOSvLoss(Source, Destination, TxHeight, RxHeight, Distance3d, vehicle_obstacles);
373 }
374 }
375
376 // add random shadows
377 ShadowFadingLoss = CalculateShadowFading(state);
378 return PathLoss + ShadowFadingLoss;
379}
380
381bool PathLossModel::IsVehicle(const FHitResult &HitInfo)
382{
383 bool Vehicle = false;
384 const FActorRegistry &Registry = mCarlaEpisode->GetActorRegistry();
385
386 const AActor *actor = HitInfo.Actor.Get();
387
388 if (actor != nullptr)
389 {
390
391 const FCarlaActor *view = Registry.FindCarlaActor(actor);
392 if (view)
393 {
395 {
396 Vehicle = true;
397 }
398 }
399 }
400 return Vehicle;
401}
402
403bool PathLossModel::HitIsSelfOrOther(const FHitResult &HitInfo, AActor *OtherActor)
404{
405 const AActor *actor = HitInfo.Actor.Get();
406 if (actor != nullptr)
407 {
408 if (actor == mActorOwner)
409 {
410 return true;
411 }
412 else if (actor == OtherActor)
413 {
414 return true;
415 }
416 }
417 return false;
418}
419
420bool PathLossModel::GetLocationIfVehicle(const FVector CurrentActorLocation, const FHitResult &HitInfo, const double reference_z, FVector &location)
421{
422 // reference_z in cm
423 bool Vehicle = false;
424 const FActorRegistry &Registry = mCarlaEpisode->GetActorRegistry();
425
426 const AActor *actor = HitInfo.Actor.Get();
427
428 if (actor != nullptr)
429 {
430
431 const FCarlaActor *view = Registry.FindCarlaActor(actor);
432 if (view)
433 {
435 {
436 Vehicle = true;
437 location = actor->GetTransform().GetLocation();
438 location.Z = location.Z - reference_z + (actor->GetSimpleCollisionHalfHeight() * 2.0) + 2.0;
439 location.Z = location.Z / 100.0f;
440 // cm to m
441 location.X /= 100.0f;
442 location.Y /= 100.0f;
443 }
444 }
445 }
446 return Vehicle;
447}
448
450{
451 m_fspl_d0 = 20.0 * log10(reference_distance_fspl) + 20.0 * log10(Frequency) + 20.0 * log10(4.0 * PI / c_speedoflight);
452}
453
454// Following ETSI TR 103 257-1 V1.1.1 (2019-05: from WINNER Project Board: "D5.3 - WINNER+ Final Channel Models", 30 06 2010.
456{
457
458 if (state == EPathState::NLOSb)
459 {
460 // Distance should be euclidean here.
461 return 36.85f + 30.0f * log10(Distance) + 18.9f * log10(Frequency_GHz);
462 }
463 else // LOS, NLOSv
464 {
466 {
467 return 32.4f + 20.0f * log10(Distance) + 20.0f * log10(Frequency_GHz);
468 }
469 else // Rural or Urban
470 {
471 return 38.77f + 16.7f * log10(Distance) + 18.2f * log10(Frequency_GHz);
472 }
473 }
474}
475
476// Following ETSI TR 103 257-1 V1.1.1 Table 6: Shadow-fading parameter σ for V2V
478{
479 const float Mean = 0.0f;
480 float std_dev_dB; // = 5.2;
481 if (use_etsi_fading)
482 {
483 switch (state)
484 {
485 case EPathState::LOS:
486 switch (scenario)
487 {
489 std_dev_dB = 3.3f;
490 break;
491 case EScenario::Urban:
492 std_dev_dB = 5.2f;
493 break;
494 case EScenario::Rural:
495 // no known values in ETSI Standard, take middle of Highway and Urban
496 std_dev_dB = 4.25f;
497 break;
498 }
499 break;
501 switch (scenario)
502 {
503 // Note: according to ETSI, NLOSb is not applicable in Highway scenario, only Urban
504 // we use the same std_dev for all three scenarios if in NLOSb
506 std_dev_dB = 6.8f;
507 break;
508 case EScenario::Urban:
509 std_dev_dB = 6.8f;
510 break;
511 case EScenario::Rural:
512 std_dev_dB = 6.8f;
513 break;
514 }
515 break;
517 switch (scenario)
518 {
520 std_dev_dB = 3.8f;
521 break;
522 case EScenario::Urban:
523 std_dev_dB = 5.3f;
524 break;
525 case EScenario::Rural:
526 // no known values in ETSI Standard, take middle of Highway and Urban
527 std_dev_dB = 4.55f;
528 break;
529 }
530 break;
531 }
532 }
533 else
534 {
535 // custom fading param
536 std_dev_dB = custom_fading_stddev;
537 }
538
539 // in dB
540 return mRandomEngine->GetNormalDistribution(Mean, std_dev_dB);
541}
542
543float PathLossModel::CalculateTwoRayPathLossSimple(double Distance3d, double TxHeight, double RxHeight)
544{
545 // simplified Two Ray Path Loss (https://en.wikipedia.org/wiki/Two-ray_ground-reflection_model)
546 // is only a valid assumption, if distance >> 4 pi TxHeight * RxHeight / lambda
547 // with f=5.9 Ghz -> lambda = c/ f = 0.05m
548 // and with average antenna height 2m: distance >> 1000m
549 return 40 * log10(Distance3d) - 10 * log10(TxHeight * TxHeight * RxHeight * RxHeight);
550}
551
552double PathLossModel::CalculateTwoRayPathLoss(double Distance3d, double TxHeight, double RxHeight)
553{
554 // tx and rx height in m
555 // distance 3d is LOS in m
556 double d_ground = sqrt(std::pow(Distance3d, 2) - std::pow(TxHeight - RxHeight, 2));
557
558 // reflected path
559 // d_reflection = sqrt(d_ground^2+(ht+hr)^2) -> with d_ground = sqrt(d_los^2 - (ht-hr)^2):
560 double d_refl = sqrt(std::pow(Distance3d, 2) + 4.0 * TxHeight * RxHeight);
561
562 // Sine and cosine of incident angle
563 double sin_theta = (TxHeight + RxHeight) / d_refl;
564 double cos_theta = d_ground / d_refl;
565
566 double gamma = (sin_theta - sqrt(epsilon_r - std::pow(cos_theta, 2))) / (sin_theta + sqrt(epsilon_r - std::pow(cos_theta, 2)));
567
568 double phi = (2.0 * PI / lambda * (Distance3d - d_refl));
569
570 return 20 * log10(4.0 * PI * d_ground / lambda * 1.0 / sqrt(std::pow(1 + gamma * cos(phi), 2) + std::pow(gamma, 2) * std::pow(sin(phi), 2)));
571}
EPathState
@ NLOSb
@ NLOSv
@ LOS
EScenario
@ Rural
@ Urban
@ Highway
EPathLossModel
@ Winner
A registry of all the Carla actors.
FCarlaActor * FindCarlaActor(IdType Id)
A view over an actor and its properties.
Definition CarlaActor.h:25
ActorType GetActorType() const
Definition CarlaActor.h:86
float ReceiverSensitivity
static double Frequency
float ComputeLoss(AActor *OtherActor, FVector Source, FVector Destination, double Distance3d, double TxHeight, double RxHeight, double reference_z)
Method that allow to preprocess if the rays will be traced.
double CalcVehicleLoss(const double d1, const double d2, const double h)
UWorld * mWorld
static double lambda
FVector CurrentActorLocation
static double Frequency_GHz
PathLossModel(URandomEngine *random_engine)
ActorPowerMap GetReceiveActorPowerList()
void Simulate(const std::vector< ActorPowerPair > ActorList, UCarlaEpisode *CarlaEpisode, UWorld *World)
EPathLossModel model
UCarlaEpisode * mCarlaEpisode
float path_loss_exponent
void SetScenario(EScenario scenario)
URandomEngine * mRandomEngine
float CalculatePathLoss_WINNER(EPathState state, double Distance)
void SetPathLossModel(const EPathLossModel path_loss_model)
double CalculateTwoRayPathLoss(double Distance3d, double TxHeight, double RxHeight)
static constexpr float c_speedoflight
EScenario scenario
float custom_fading_stddev
bool GetLocationIfVehicle(const FVector CurrentActorLocation, const FHitResult &HitInfo, const double reference_z, FVector &location)
float CalculateReceivedPower(AActor *OtherActor, const float OtherTransmitPower, const FVector Source, const FVector Destination, const double Distance3d, const double ht, const double ht_local, const double hr, const double hr_local, const double reference_z)
float CalculateTwoRayPathLossSimple(double Distance3d, double TxHeight, double RxHeight)
float filter_distance
double CalculateNLOSvLoss(const FVector Source, const FVector Destination, const double TxHeight, const double RxHeight, const double RxDistance3d, std::vector< FVector > &vehicle_obstacles)
void EstimatePathStateAndVehicleObstacles(AActor *OtherActor, FVector Source, double TxHeight, double RxHeight, double reference_z, EPathState &state, std::vector< FVector > &vehicle_obstacles)
void SetParams(const float TransmitPower, const float ReceiverSensitivity, const float Frequency, const float combined_antenna_gain, const float path_loss_exponent, const float reference_distance_fspl, const float filter_distance, const bool use_etsi_fading, const float custom_fading_stddev)
AActor * mActorOwner
float reference_distance_fspl
ActorPowerMap mReceiveActorPowerList
bool HitIsSelfOrOther(const FHitResult &HitInfo, AActor *OtherActor)
void SetOwner(AActor *Owner)
TArray< FHitResult > HitResult
float combined_antenna_gain
const double epsilon_r
float CalculateShadowFading(EPathState state)
bool IsVehicle(const FHitResult &HitInfo)
A simulation episode.
const FActorRegistry & GetActorRegistry() const
float GetNormalDistribution(float Mean, float StandardDeviation)