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