NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
LTENR_Fading.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* This source code is licensed per the NetSim license agreement. *
5* No portion of this source code may be used as the basis for a derivative work. *
6* *
7* Author: Suraj(Rician) && Charu(Rayleigh) *
8************************************************************************************/
9
10#include <stdlib.h>
11#include <math.h>
12#include "NetSim_utility.h"
13#include "LTENR_Fading.h"
14#include "lapacke.h"
15#include "main.h"
16
17#ifndef M_PI
18#define M_PI 3.14159265358979323846
19#endif
20
21#define MAX_RETRIES 10
22#define MIN(a, b) ((a) < (b) ? (a) : (b))
23
24/* Box–Muller Gaussian */
25static double gaussian_random(void) {
26 double U1 = NETSIM_RAND_01();
27 double U2 = NETSIM_RAND_01();
28 return sqrt(-2.0 * log(U1)) * cos(2.0 * M_PI * U2);
29}
30
31/* Descending sort comparator */
32static int cmp_desc(const void* a, const void* b) {
33 double da = *(double*)a, db = *(double*)b;
34 if (da < db) return 1;
35 if (da > db) return -1;
36 return 0;
37}
38
39/* Rayleigh H entries */
40static void generate_rayleigh_H(lapack_complex_double* H, UINT NR, UINT NT) {
41 for (UINT i = 0; i < NR * NT; i++) {
42 H[i].real = gaussian_random() / sqrt(2.0);
43 H[i].imag = gaussian_random() / sqrt(2.0);
44 }
45}
46
47/* Rician H entries */
48static void generate_rician_H(lapack_complex_double* H, UINT NR, UINT NT, double K) {
49 double mu = sqrt(K / (2.0 * (K + 1.0)));
50 double sigma = sqrt(1.0 / (2.0 * (K + 1.0)));
51 for (UINT i = 0; i < NR * NT; i++) {
52 H[i].real = mu + sigma * gaussian_random();
53 H[i].imag = mu + sigma * gaussian_random();
54 }
55}
56
57/* Unified Rayleigh/Rician eigen-solver */
58void LTENR_Beamforming_GetValue(
59 UINT NT, UINT NR,
60 UINT fastFadingModel,
61 double K_factor,
62 double** eigenvalues)
63{
64 UINT layers = MIN(NT, NR);
65 double* results = malloc(layers * sizeof(*results));
66 if (!results) { *eigenvalues = NULL; return; }
67
68 lapack_complex_double* H = malloc(NR * NT * sizeof(*H));
69 lapack_complex_double* G = malloc(NR * NR * sizeof(*G));
70 double* w = malloc(NR * sizeof(*w));
71 if (!H || !G || !w) {
72 free(results); free(H); free(G); free(w);
73 *eigenvalues = NULL; return;
74 }
75
76 lapack_int info = -1;
77 int retry = 0;
78 while (retry < MAX_RETRIES && info != 0) {
79 if (fastFadingModel == FADING_MODEL_RICIAN) {
80 generate_rician_H(H, NR, NT, K_factor);
81 }
82 else if (fastFadingModel == FADING_MODEL_RAYLEIGH) {
83 // Default to Rayleigh for any other model
84 generate_rayleigh_H(H, NR, NT);
85 }
86
87 /* Build G = H * H^H */
88 for (UINT i = 0; i < NR; i++) {
89 for (UINT j = 0; j < NR; j++) {
90 lapack_complex_double sum = { 0.0, 0.0 };
91 for (UINT k = 0; k < NT; k++) {
92 double ar = H[i * NT + k].real, ai = H[i * NT + k].imag;
93 double br = H[j * NT + k].real, bi = -H[j * NT + k].imag;
94 sum.real += ar * br - ai * bi;
95 sum.imag += ar * bi + ai * br;
96 }
97 G[i * NR + j] = sum;
98 }
99 }
100
101 info = LAPACKE_zheevd(LAPACK_ROW_MAJOR, 'N', 'U', NR, G, NR, w);
102 if (info != 0) retry++;
103 }
104
105 if (info != 0) {
106 for (UINT i = 0; i < layers; i++) results[i] = 0.0;
107 }
108 else {
109 qsort(w, NR, sizeof(*w), cmp_desc);
110 for (UINT i = 0; i < layers; i++) results[i] = w[i];
111 }
112
113 for (int i = 0; i < layers; i++) {
114 double v = results[i];
115 if (v < 1e-12) v = 1e-12; // avoid log(0)
116 results[i] = 10.0 * log10(v); // convert to dB
117 }
118
119 for (UINT i = 0; i < layers; i++) {
120 (*eigenvalues)[i] = results[i];
121 }
122 free(results);
123 free(H); free(G); free(w);
124}