NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
NTN_PropagationModel.c
1#include "NTN_PropagationModel.h"
2#include "LTENR_PropagationModel.h"
3#include "LTE_NR.h"
4#include "LTENR_PHY.h"
5#include "NTN.h"
6
7#define EARTH_RADIUS 6371000
8#define BOLTZMANN -228.6 // dBW/K/Hz
9#define CIR_MW_TO_DBM(mw) ((mw) <= ZERO_MW?NEGATIVE_DBM:-10.0*log10(mw))
10#define CIR_DBM_TO_MW(dbm) ((dbm) == NEGATIVE_DBM? 0.0: pow(10.0,(-dbm)/10.0))
11
12#define NTN_RX_ANTENNA_TEMPERATURE 290
13
14static bool isNTNScenarioVar = false;
15static ptrNTN_PROPAGATIONCONFIG ntnInfo = NULL;
16
17bool isNTNScenario()
18{
19 //return false;
20 return isNTNScenarioVar;
21}
22
23void setNTNpropagationInfo(ptrNTN_PROPAGATIONCONFIG propagation) {
24 ntnInfo = propagation;
25}
26
27ptrNTN_PROPAGATIONCONFIG getNTN_PropInfo()
28{
29 return ntnInfo;
30}
31
32void setNTNScenario()
33{
34 isNTNScenarioVar = true;
35 return ;
36}
37
38
39double calculateSlantRange(double altitude, double elevationAngle_rad)
40{
41 double sinAlpha = sin(elevationAngle_rad);
42 double d = sqrt(pow(EARTH_RADIUS * sinAlpha, 2) + pow(altitude, 2) + 2 * altitude * EARTH_RADIUS) - EARTH_RADIUS * sinAlpha;
43 return d;
44}
45
46double calculateNTN_SNR(ptrLTENR_PROPAGATIONINFO propInfo, double beamformingGain) {
47 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
48 double snr, eirp_dBW;
49 eirp_dBW = ntnInfo->eirpDensity + MW_TO_DBM(ntnInfo->channelBandwidth);
50
51 ntnInfo->eirp_dBW = eirp_dBW;
52 double B_db = MW_TO_DBM(ntnInfo->channelBandwidth * pow(10, 6));
53 snr = eirp_dBW + propInfo->angularAntennaGain_dB + propInfo->rxG_T - BOLTZMANN - propInfo->dTotalLoss - B_db + beamformingGain;
54
55 return snr;
56}
57
58double calculateFreeSpacePathLoss(ptrLTENR_PROPAGATIONINFO propInfo)
59{
60 NETSIM_ID ueId = propInfo->ueId;
61
62 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
63
64 double altitude = DEVICE_POSITION(ntnInfo->ntnId)->Z;
65
66 propInfo->slantHeight = calculateSlantRange(altitude, propInfo->elevationAngle_rad);
67
68 return 32.45 + 20 * log10(propInfo->centralFrequency_GHz) + 20 * log10(propInfo->slantHeight);
69}
70
71static double NTN_log_normal_distribution(ptrNTN_PROPAGATIONCONFIG info, double std)
72{
73 double ldRandomNumber = 0.0;
74 double fFac, fRsq, fV1, fV2;
75 double st, phase, loss;
76
77 if (info->SHADOWVAR.isConstructiveShadow == 0)
78 {
79 do
80 {
81 ldRandomNumber = RANDOM_01;
82 fV1 = (double)(2.0 * ldRandomNumber - 1.0);
83 //calculate the Random number from this function
84 ldRandomNumber = RANDOM_01;
85 fV2 = (double)(2.0 * ldRandomNumber - 1.0);
86 fRsq = fV1 * fV1 + fV2 * fV2;
87 } while (fRsq >= 1.0 || fRsq == 0.0);
88
89 fFac = (double)(sqrt(-2.0 * log(fRsq) / fRsq));
90 info->SHADOWVAR.Gset = fV1 * fFac;
91 info->SHADOWVAR.Iset = fV2 * fFac;
92
93 st = info->SHADOWVAR.Gset; //st = Gset || Iset;
94 info->SHADOWVAR.isConstructiveShadow = 1;
95 }
96 else
97 {
98 st = info->SHADOWVAR.Iset;
99 info->SHADOWVAR.isConstructiveShadow = 0;
100 }
101
102 phase = RANDOM_01;
103 if (phase <= 0.5)
104 loss = -1 * std * st;
105 else
106 loss = std * st;
107
108 return loss;
109}
110
111void calculateNTN_totalloss(ptrLTENR_PROPAGATIONINFO propInfo)
112{
113
114 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
115
116 NETSIM_ID ueId = propInfo->ueId;
117
118 if (ntnInfo->pathLossModel == NTN_PATHLOSS_MODEL_FREE_SPACE)
119 {
120 propInfo->dPathLoss = calculateFreeSpacePathLoss(propInfo);
121 }
122 else
123 propInfo->dPathLoss = 0;
124
125 if (ntnInfo->shadowFadingModel == NTN_SHADOWFADING_MODEL_LOGNORMAL)
126 {
127 propInfo->dShadowFadingLoss = calculateNTNshadowloss(propInfo);
128 }
129 else
130 propInfo->dShadowFadingLoss = 0;
131
132 if (ntnInfo->clutterlossModel == NTN_CLUTTERLOSS_MODEL_TR38_811)
133 {
134 propInfo->dClutterLoss = calculateNTNclutterloss(propInfo);
135 }
136 else
137 propInfo->dClutterLoss = 0;
138
139 propInfo->dAdditionalLoss = ntnInfo->additionalLoss;
140
141 propInfo->dTotalLoss = propInfo->dPathLoss + propInfo->dShadowFadingLoss
142 + propInfo->dAdditionalLoss + propInfo->dClutterLoss;
143
144}
145
146ptrBeamNode addBeamCenters(UINT beamCount)
147{
148 char filename[BUFSIZ];
149 sprintf(filename, "%s\\Default\\CenterPoints.csv", pszIOPath);
150
151 FILE* file = fopen(filename, "r");
152 if (file == NULL) {
153 fprintf(stderr, "Error opening file\n");
154 return NULL;
155 }
156
157 ptrBeamNode head = NULL;
158 ptrBeamNode tail = NULL;
159
160 UINT cellId, id = 1;
161 int channelId;
162 double x, y;
163 char buffer[256];
164
165 // Read the CSV file line by line
166 while (fgets(buffer, sizeof(buffer), file) != NULL) {
167 if (sscanf(buffer, "%d,%lf,%lf,%d", &cellId, &x, &y, &channelId) == 4)
168 {
169 ptrBeamNode newBeam = (ptrBeamNode)malloc(sizeof(BeamNode));
170 if (!newBeam) {
171 fprintf(stderr, "Memory allocation failed\n");
172 fclose(file);
173 return NULL;
174 }
175 newBeam->beamCoord = (NetSim_COORDINATES*)malloc(sizeof(NetSim_COORDINATES));
176
177 // Set the beam data
178 newBeam->beamId = id;
179 newBeam->beamCoord->X = x;
180 newBeam->beamCoord->Y = y;
181 newBeam->beamChannelId = channelId;
182 newBeam->next = NULL;
183
184
185 if (head == NULL) {
186 head = newBeam;
187 }
188 else {
189 tail->next = newBeam;
190 }
191 tail = newBeam;
192 id += 1;
193 }
194 }
195 if (id - 1 != beamCount)
196 {
197 fprintf(stderr, "\nCount of beams not matching");
198 }
199 fclose(file); // Close the file
200 return head; // Return the head of the linked list
201}
202
203void calculateNTNAntennaGain(ptrLTENR_PROPAGATIONINFO propInfo)
204{
205 CalculateTheta(propInfo); // Updating the angle from the current best beam
206
207 NETSIM_ID ueId = propInfo->ueId;
208 NetSim_COORDINATES* uePos = DEVICE_POSITION(ueId);
209 double antennaGain;
210
211 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
212
213 double k = 2 * M_PI * propInfo->centralFrequency_GHz * pow(10, 9) / (3 * pow(10, 8)); // k is wave number,
214
215 antennaGain = calculateAntennaGain(propInfo->theta_rad, k, ntnInfo->antennaAperture);
216
217 propInfo->angularAntennaGain_dB = antennaGain;
218 propInfo->netAntennaGain_dB = propInfo->angularAntennaGain_dB + ntnInfo->maxAntennaGain;
219 return;
220}
221
222static void updateNTN_elevationAngle(ptrLTENR_PROPAGATIONINFO propInfo)
223{
224 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
225
226 double x1 = DEVICE_POSITION(ntnInfo->ntnId)->X;
227 double y1 = DEVICE_POSITION(ntnInfo->ntnId)->Y;
228 double z1 = DEVICE_POSITION(ntnInfo->ntnId)->Z;
229
230 double x2 = DEVICE_POSITION(propInfo->ueId)->X;
231 double y2 = DEVICE_POSITION(propInfo->ueId)->Y;
232
233 double dis = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
234 double theta = atan(z1 / dis);
235 propInfo->elevationAngle_rad = theta;
236 return;
237}
238
239void allocateInfo(ptrLTENR_PROPAGATIONINFO propInfo)
240{
241 // Allocate and copy pointer members separately
242 UINT layerCount = min(propInfo->downlink.txAntennaCount, propInfo->downlink.rxAntennaCount);
243 propInfo->downlink.rxPower_dbm = malloc(layerCount * sizeof(double));
244 propInfo->downlink.SNR_db = malloc(layerCount * sizeof(double));
245 propInfo->downlink.SINR_db = malloc(layerCount * sizeof(double));
246 propInfo->downlink.EB_by_N0 = malloc(layerCount * sizeof(double));
247 propInfo->downlink.InterferencePower_dbm = malloc(layerCount * sizeof(double));
248 propInfo->downlink.spectralEfficiency = malloc(layerCount * sizeof(double));
249
250 layerCount = min(propInfo->uplink.txAntennaCount, propInfo->uplink.rxAntennaCount);
251
252 propInfo->uplink.rxPower_dbm = malloc(layerCount * sizeof(double));
253 propInfo->uplink.SNR_db = malloc(layerCount * sizeof(double));
254 propInfo->uplink.SINR_db = malloc(layerCount * sizeof(double));
255 propInfo->uplink.EB_by_N0 = malloc(layerCount * sizeof(double));
256 propInfo->uplink.InterferencePower_dbm = malloc(layerCount * sizeof(double));
257 propInfo->uplink.spectralEfficiency = malloc(layerCount * sizeof(double));
258}
259
260static void freeInfo(ptrLTENR_PROPAGATIONINFO propInfo)
261{
262 if (!propInfo) return;
263
264 free(propInfo->downlink.rxPower_dbm);
265 free(propInfo->downlink.SNR_db);
266 free(propInfo->downlink.SINR_db);
267 free(propInfo->downlink.EB_by_N0);
268 free(propInfo->downlink.InterferencePower_dbm);
269 free(propInfo->downlink.spectralEfficiency);
270
271 free(propInfo->uplink.rxPower_dbm);
272 free(propInfo->uplink.SNR_db);
273 free(propInfo->uplink.SINR_db);
274 free(propInfo->uplink.EB_by_N0);
275 free(propInfo->uplink.InterferencePower_dbm);
276 free(propInfo->uplink.spectralEfficiency);
277
278}
279
280static void deepCopyPropagationInfo(ptrLTENR_PROPAGATIONINFO propInfo, ptrLTENR_PROPAGATIONINFO tempInfo)
281{
282 if (!propInfo || !tempInfo) {
283 fprintf(stderr, "PorpInfo not copied");
284 return;
285 }
286 UINT layerCount = propInfo->downlink.layerCount;
287
288 propInfo->angularAntennaGain_dB = tempInfo->angularAntennaGain_dB;
289 propInfo->netAntennaGain_dB = tempInfo->netAntennaGain_dB;
290 propInfo->rxG_T = tempInfo->rxG_T;
291 propInfo->selectedBeamId = tempInfo->selectedBeamId;
292
293 propInfo->slantHeight = tempInfo->slantHeight;
294 propInfo->theta_rad = tempInfo->theta_rad;
295 propInfo->dPathLoss = tempInfo->dPathLoss;
296 propInfo->dShadowFadingLoss = tempInfo->dShadowFadingLoss;
297 propInfo->dAdditionalLoss = tempInfo->dAdditionalLoss;
298 propInfo->dClutterLoss = tempInfo->dClutterLoss;
299 propInfo->dTotalLoss = tempInfo->dTotalLoss;
300 propInfo->downlink.thermalNoise = tempInfo->downlink.thermalNoise;
301
302 for (int layerId = 0; layerId < layerCount; layerId++)
303 {
304 propInfo->downlink.SNR_db[layerId] = tempInfo->downlink.SNR_db[layerId];
305 propInfo->downlink.rxPower_dbm[layerId] = tempInfo->downlink.rxPower_dbm[layerId];
306 propInfo->downlink.EB_by_N0[layerId] = tempInfo->downlink.EB_by_N0[layerId];
307 propInfo->downlink.spectralEfficiency[layerId] = tempInfo->downlink.spectralEfficiency[layerId];
308 propInfo->downlink.SINR_db[layerId] = tempInfo->downlink.SINR_db[layerId];
309 propInfo->downlink.InterferencePower_dbm[layerId] = tempInfo->downlink.InterferencePower_dbm[layerId];
310 }
311
312 layerCount = propInfo->uplink.layerCount;
313
314 for (int layerId = 0; layerId < layerCount; layerId++)
315 {
316 propInfo->uplink.SNR_db[layerId] = tempInfo->uplink.SNR_db[layerId];
317 propInfo->uplink.rxPower_dbm[layerId] = tempInfo->uplink.rxPower_dbm[layerId];
318 propInfo->uplink.EB_by_N0[layerId] = tempInfo->uplink.EB_by_N0[layerId];
319 propInfo->uplink.spectralEfficiency[layerId] = tempInfo->uplink.spectralEfficiency[layerId];
320 propInfo->uplink.SINR_db[layerId] = tempInfo->uplink.SINR_db[layerId];
321 propInfo->uplink.InterferencePower_dbm[layerId] = tempInfo->uplink.InterferencePower_dbm[layerId];
322 }
323 return;
324}
325
326void NTN_BestBeamSelectionAlgorithm(ptrLTENR_PROPAGATIONINFO propInfo,int CA_ID, UINT layerId)
327{
328 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
329
330 ptrBeamNode tempbeamList = ntnInfo->beamList;
331 double bestSNR = NEGATIVE_DBM, snr = NEGATIVE_DBM; // Minimum snr value
332 double interference;
333
334 updateNTNBandwidth(propInfo);
335 updateNTN_elevationAngle(propInfo);
336 updateNoisePower(propInfo);
337
338 ptrLTENR_PROPAGATIONINFO tempInfo = (ptrLTENR_PROPAGATIONINFO)malloc(sizeof(LTENR_PROPAGATIONINFO));
339
340 if (!tempInfo)
341 {
342 printf("Memory allocation failed.\n");
343 return;
344 }
345
346 memcpy(tempInfo, propInfo, sizeof(*propInfo));
347
348 allocateInfo(tempInfo);
349
350 while (tempbeamList)
351 {
352 tempInfo->selectedBeamId = tempbeamList->beamId;
353
354 calculateNTN_totalloss(tempInfo);
355
356 calculateNTNAntennaGain(tempInfo);
357
358 updateNTN_RxG_T(tempInfo);
359
360 // Calculate SINR for the current beam
361 tempInfo->downlink.SNR_db[layerId] = calculateNTN_SNR(tempInfo, LTENR_BeamForming_Downlink_GetValue(tempInfo, layerId));
362
363 updateNTNRxPower(tempInfo, layerId);
364
365 NTN_calculateSINR(tempInfo, layerId);
366
367 updateNTN_EB_by_N0(tempInfo, layerId);
368
369 snr = tempInfo->downlink.SNR_db[layerId];
370
371 NTN_plotUeAssociation(tempInfo, CA_ID, layerId, false);
372
373 // Update the best beam based on the SINR value
374 if (snr > bestSNR)
375 {
376 deepCopyPropagationInfo(propInfo, tempInfo);
377 bestSNR = snr;
378 }
379 tempbeamList = tempbeamList->next;
380 }
381 NTN_plotUeAssociation(propInfo,CA_ID,layerId, true);
382
383 freeInfo(tempInfo);
384 free(tempInfo);
385
386 return;
387}
388
389static double NTN_calculateCIR_InterferencePower(ptrLTENR_PROPAGATIONINFO propInfo, UINT layerId) {
390
391 double snr_mw, noise_mw, sinr_mw, interference_mw;
392 noise_mw = DBM_TO_MW(propInfo->downlink.thermalNoise);
393 snr_mw = DBM_TO_MW(propInfo->downlink.SNR_db[layerId]);
394 sinr_mw = DBM_TO_MW(propInfo->downlink.SINR_db[layerId]);
395
396 interference_mw = noise_mw * (snr_mw / sinr_mw - 1);
397
398 return MW_TO_DBM(interference_mw);
399}
400
401void NTN_calculateSINR(ptrLTENR_PROPAGATIONINFO propInfo, UINT layerId) {
402
403 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
404
405 if (ntnInfo->interferenceModel == NTN_NONE) {
406 propInfo->downlink.InterferencePower_dbm[layerId] = NEGATIVE_DBM;
407 propInfo->downlink.SINR_db[layerId] = propInfo->downlink.SNR_db[layerId];
408 }
409 else if (ntnInfo->interferenceModel == NTN_CIR) {
410 propInfo->downlink.SINR_db[layerId] = NTN_calculateCIR_Sinr(propInfo->downlink.SNR_db[layerId], ntnInfo->carrier_InterferenceRatio);
411 propInfo->downlink.InterferencePower_dbm[layerId] = NTN_calculateCIR_InterferencePower(propInfo,layerId);
412
413 }
414 else if (ntnInfo->interferenceModel == NTN_EXACT_GEOMETRIC_MODEL)
415 {
416 double interferencePower = calculateInterferencePower(propInfo, layerId);
417 propInfo->downlink.InterferencePower_dbm[layerId] = interferencePower;
418 propInfo->downlink.SINR_db[layerId] = calculate_sinr((propInfo->downlink.SNR_db[layerId] + propInfo->downlink.thermalNoise), interferencePower, ntnInfo->channelBandwidth);
419 }
420 else {
421 fprintf(stderr, "Unknown Interference Model");
422 propInfo->downlink.InterferencePower_dbm[layerId] = NEGATIVE_DBM;
423 propInfo->downlink.SINR_db[layerId] = propInfo->downlink.SNR_db[layerId];
424 }
425 return;
426}
427
428static double Magnitude(NetSim_COORDINATES* p) {
429 return sqrt(p->X * p->X + p->Y * p->Y + p->Z * p->Z);
430}
431
432// Function to calculate dot product of two vectors
433static double DotProduct(NetSim_COORDINATES* v1, const NetSim_COORDINATES* v2) {
434 return v1->X * v2->X + v1->Y * v2->Y + v1->Z * v2->Z;
435}
436
437
438void CalculateTheta(ptrLTENR_PROPAGATIONINFO propInfo) {
439 // Calculate vectors
440 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
441
442 NetSim_COORDINATES* beam = getBeamCoordinates(propInfo->selectedBeamId);
443 NetSim_COORDINATES* satellite = DEVICE_POSITION(ntnInfo->ntnId);
444 NetSim_COORDINATES* receiver = DEVICE_POSITION(propInfo->ueId);
445
446 NetSim_COORDINATES v1 = {
447 .X = beam->X - satellite->X,
448 .Y = beam->Y - satellite->Y,
449 .Z = beam->Z - satellite->Z
450 };
451 NetSim_COORDINATES v2 = {
452 .X = receiver->X - satellite->X,
453 .Y = receiver->Y - satellite->Y,
454 .Z = receiver->Z - satellite->Z
455 };
456
457 // Calculate magnitudes
458 double mag_v1 = Magnitude(&v1);
459 double mag_v2 = Magnitude(&v2);
460
461 // Normalize vectors
462 NetSim_COORDINATES v1_norm = {
463 .X = v1.X / mag_v1,
464 .Y = v1.Y / mag_v1,
465 .Z = v1.Z / mag_v1 };
466
467 NetSim_COORDINATES v2_norm = {
468 .X = v2.X / mag_v2,
469 .Y = v2.Y / mag_v2,
470 .Z = v2.Z / mag_v2 };
471
472 // Calculate dot product of normalized vectors
473 double dot_product = DotProduct(&v1_norm, &v2_norm);
474
475 // Calculate theta (angle in radians)
476 propInfo->theta_rad = acos(dot_product);
477 return;
478}
479
480static void NTN_setLOS_state(ptrLTENR_PROPAGATIONINFO propInfo)
481{
482 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
483 double LOS_probability;
484 double r = RANDOM_01;
485
486 if (ntnInfo->los_mode != NTN_LOS_MODE_USER_DEFINED)
487 {
488 double elevationAngle = propInfo->elevationAngle_rad * 180 / M_PI;
489 LOS_probability = NTNget_LOS_probability(ntnInfo->outScenario, elevationAngle);
490 }
491 else
492 LOS_probability = ntnInfo->los_probability;
493
494 if (r <= LOS_probability)
495 ntnInfo->state = NTN_STATE_LOS;
496 else
497 ntnInfo->state = NTN_STATE_NLOS;
498 return;
499}
500
501double calculateNTNshadowloss(ptrLTENR_PROPAGATIONINFO propInfo)
502{
503 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
504
505 double elevationAngle = propInfo->elevationAngle_rad * 180 / M_PI;
506 NTN_setLOS_state(propInfo);
507 double stdDeviation = get_shadowingSD(ntnInfo->outScenario, ntnInfo->state, ntnInfo->carrierBand, elevationAngle);
508 ntnInfo->standardDeviation = stdDeviation;
509 return NTN_log_normal_distribution(ntnInfo, stdDeviation);
510}
511
512double calculateNTNclutterloss(ptrLTENR_PROPAGATIONINFO propInfo)
513{
514 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
515
516 double elevationAngle = propInfo->elevationAngle_rad * 180 / M_PI;
517 NTN_setLOS_state(propInfo);
518
519 return get_clutterloss(ntnInfo->outScenario, ntnInfo->state, ntnInfo->carrierBand, elevationAngle);
520
521}
522
523void updateNTNBandwidth(ptrLTENR_PROPAGATIONINFO propInfo) {
524
525 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
526 double totalBandwidth = propInfo->bandwidth_MHz;
527
528 if (ntnInfo->ntnFR_factor != NTN_FREQUENCY_REUSE_FACTOR_1)
529 {
530 totalBandwidth -= ntnInfo->guardBand_MHz * (ntnInfo->channelCount - 1);
531 ntnInfo->channelBandwidth = totalBandwidth / ntnInfo->channelCount;
532 }
533 else
534 ntnInfo->channelBandwidth = totalBandwidth;
535 return;
536}
537
538double calculateAntennaGain(double theta, double k, double a)
539{
540 // k is wawenumber, a is antenna apperture
541 if (theta == 0)
542 {
543 return 0;
544 }
545
546 else if (fabs(theta) <= M_PI / 2) {
547 // Section 6.4.1 3GPP TR 38.811
548 //double x =2*M_PI*a*sin(theta);
549 double x = k * a * sin(theta);
550 double besselJ1 = _j1(x);
551 double J1_x = besselJ1 / x;
552 double gain = 4 * pow(J1_x, 2);
553 double maxGain_dbm = MW_TO_DBM(gain);
554 return maxGain_dbm;
555 }
556 else {
557 fprintf(stderr, "Theta not in range");
558 return 0.0; // Gain is zero if theta is outside the valid range
559 }
560}
561
562double getDistancefromBeam(ptrLTENR_PROPAGATIONINFO propInfo)
563{
564 ptrBeamNode tempbeamList = ntnInfo->beamList;
565
566 NetSim_COORDINATES* uePos = DEVICE_POSITION(propInfo->ueId);
567
568 while (tempbeamList)
569 {
570 if (propInfo->selectedBeamId == tempbeamList->beamId)
571 {
572 double dx = uePos->X - tempbeamList->beamCoord->X;
573 double dy = uePos->Y - tempbeamList->beamCoord->Y;
574 double distance = sqrt(dx * dx + dy * dy);
575 return distance;
576 }
577 tempbeamList = tempbeamList->next;
578 }
579 return -1;
580}
581
582void updateNTN_RxG_T(ptrLTENR_PROPAGATIONINFO propInfo) {
583 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
584
585 ptrLTENR_UEPHY uePhy = LTENR_UEPHY_GET(propInfo->ueId, propInfo->ueIf);
586
587 propInfo->rxG_T = uePhy->ueRxAntennaGain - (MW_TO_DBM(NTN_RX_ANTENNA_TEMPERATURE) + ntnInfo->noiseFigure);
588 return;
589}
590
591void updateNTN_EB_by_N0(ptrLTENR_PROPAGATIONINFO propInfo, UINT layerId)
592{
593 propInfo->downlink.EB_by_N0[layerId] = DBM_TO_MW(propInfo->downlink.SINR_db[layerId]);
594 propInfo->downlink.spectralEfficiency[layerId] = log2(1 + propInfo->downlink.EB_by_N0[layerId]);
595}
596
597void updateNTNRxPower(ptrLTENR_PROPAGATIONINFO propInfo, UINT layerId)
598{
599 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
600
601 ptrLTENR_UEPHY uePhy = LTENR_UEPHY_GET(propInfo->ueId, propInfo->ueIf);
602 propInfo->downlink.rxPower_dbm[layerId] = propInfo->downlink.SNR_db[layerId] + propInfo->downlink.thermalNoise;
603}
604
605void updateNTN_TxPower(ptrLTENR_PROPAGATIONINFO propInfo, UINT layerId) {
606
607 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
608 double eirp_dBW = ntnInfo->eirpDensity + MW_TO_DBM(ntnInfo->channelBandwidth);
609 double txPowerDBm = eirp_dBW + 30 - ntnInfo->maxAntennaGain;
610 propInfo->downlink.totaltxpower_dbm = txPowerDBm;
611 return;
612}
613
614double calculateInterferencePower(ptrLTENR_PROPAGATIONINFO propInfo, UINT layerId) {
615
616 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
617 ptrBeamNode tempbeamList = ntnInfo->beamList;
618 double interferenceLinear = 0, snr = 0;
619 UINT currChannelId;
620
621 while (tempbeamList)
622 {
623 if (tempbeamList->beamId == propInfo->selectedBeamId) {
624 currChannelId = tempbeamList->beamChannelId;
625 break;
626 }
627 tempbeamList = tempbeamList->next;
628 }
629 ptrLTENR_PROPAGATIONINFO tempInfo = (ptrLTENR_PROPAGATIONINFO)malloc(sizeof(LTENR_PROPAGATIONINFO));
630 if (!tempInfo)
631 {
632 printf("Memory allocation failed.\n");
633 return;
634 }
635
636 memcpy(tempInfo, propInfo, sizeof(LTENR_PROPAGATIONINFO));
637 allocateInfo(tempInfo);
638 tempbeamList = ntnInfo->beamList;
639
640 while (tempbeamList)
641 {
642 tempInfo->selectedBeamId = tempbeamList->beamId;
643 // Calculate Rx power for all the beams with same channel Id
644 if (tempbeamList->beamId != propInfo->selectedBeamId && tempbeamList->beamChannelId == currChannelId) {
645
646 calculateNTN_totalloss(tempInfo);
647 calculateNTNAntennaGain(tempInfo);
648
649 updateNTN_RxG_T(tempInfo);
650
651 // Calculate SINR for the current beam
652 snr = calculateNTN_SNR(tempInfo, LTENR_BeamForming_Downlink_GetValue(tempInfo, layerId));
653 updateNTNRxPower(tempInfo, layerId);
654 interferenceLinear += DBM_TO_MW(snr + propInfo->downlink.thermalNoise);
655 }
656 tempbeamList = tempbeamList->next;
657 }
658 freeInfo(tempInfo);
659 propInfo->downlink.InterferencePower_dbm[layerId] = MW_TO_DBM(interferenceLinear);
660 return MW_TO_DBM(interferenceLinear);
661}
662
663double NTN_calculateCIR_Sinr(double snr, double cir)
664{
665 double snr_mw, cir_mw, sinr_mw;
666 snr_mw = CIR_DBM_TO_MW(snr);
667 cir_mw = CIR_DBM_TO_MW(cir);
668 sinr_mw = snr_mw + cir_mw;
669 return CIR_MW_TO_DBM(sinr_mw);
670}
671
672
673NetSim_COORDINATES* getBeamCoordinates( UINT id) {
674
675 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
676
677 ptrBeamNode beamList = ntnInfo->beamList;
678 while (beamList) {
679 if (beamList->beamId == id)
680 return beamList->beamCoord;
681 beamList = beamList->next;
682 }
683 return NULL;
684}
685
686int getBeamChannelId( UINT id) {
687
688 ptrNTN_PROPAGATIONCONFIG ntnInfo = getNTN_PropInfo();
689 ptrBeamNode beamList = ntnInfo->beamList;
690 while (beamList) {
691 if (beamList->beamId == id)
692 return beamList->beamChannelId;
693 beamList = beamList->next;
694 }
695 return -1;
696}