1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdlib.h>
7 #include <math.h>
8 #include <complex.h>
9 #include "bs_tracing.h"
10 #include "bs_types.h"
11 
12 /**
13  * Initialize the random generators
14  */
bs_random_init(unsigned int seed)15 int bs_random_init(unsigned int seed){
16   srandom(seed);
17   srand(seed);
18   return 0;
19 }
20 
21 /**
22  * Free any memory this module may have allocated
23  */
bs_random_free()24 void bs_random_free(){
25 
26 }
27 
28 /**
29  * Generate a Gausian random number N(0,1): with mean 0 and variance 1
30  * In general to get a N(ave,std) do:
31  *   Random_Gaus()*std + ave;
32  *
33  * It uses the Marsaglia polar method:
34  *  http://en.wikipedia.org/wiki/Marsaglia_polar_method
35  *  Based on the "MIT like" licensed code
36  *  ftp://ftp.taygeta.com/pub/c/boxmuller.c:
37  *  "(c) Copyright 1994, Everett F. Carter Jr.
38  *       Permission is granted by the author to use
39  *       this software for any application provided this
40  *       copyright notice is preserved."
41  *
42  *  but with div by 0 protection
43  */
bs_random_Gaus()44 double bs_random_Gaus(){
45   double x,w;
46   static double y;
47   static int use_last = 0;
48   double toreturn;
49 
50   if (use_last == 0) {
51     do {
52       x = 2*((double)random() / RAND_MAX)-1;
53       y = 2*((double)random() / RAND_MAX)-1;
54 
55       w = x * x + y * y;
56     } while (w >= 1 || w == 0);
57 
58     w = sqrt(-2.0 * log(w) / w);
59     toreturn = x * w;
60     y = y * w;
61   } else {
62     toreturn = y;
63   }
64 
65   use_last = 1 - use_last;
66 
67   return toreturn;
68 }
69 
70 /**
71  * Like Random_Gaus but return a complex double instead
72  * Returns a sample of a N(0,1) + 1i*N(0,1) with uncorrelated I and Q parts
73  */
bs_random_Gaus_c()74 double complex bs_random_Gaus_c(){
75   double x, y, w;
76   double complex toreturn;
77 
78     do {
79       x = 2*((double)random() / RAND_MAX)-1;
80       y = 2*((double)random() / RAND_MAX)-1;
81 
82       w = x * x + y * y;
83     } while(w >= 1 || w == 0);
84     w = sqrt(-2.0 * log(w) / w);
85 
86     toreturn = x * w + ( y * w )*I;
87 
88   return toreturn;
89 }
90 
91 /**
92  * Fill in a buffer of size <size> with complex random gausian numbers
93  * each a sample of a N(0,1) + 1i*N(0,1) with uncorrelated I and Q parts
94  */
bs_random_Gaus_c_buffer(double complex * buffer,uint size)95 void bs_random_Gaus_c_buffer(double complex* buffer, uint size){
96   double x, y, w;
97   uint i;
98 
99   //TOOPT: this takes a sizeable amount of time for the 2G4_channel_Indoorv1,
100   // it could make sense to optimize it to avoid using log
101   // roughly time is used as follows: log: 383/856, sqrt = 12/856,  random 133*2/856
102   // an option would be: http://en.wikipedia.org/wiki/Ziggurat_algorithm
103 
104   for (i = 0 ; i < size; i++){
105     do {
106       x = 2*((double)random() / RAND_MAX)-1;
107       y = 2*((double)random() / RAND_MAX)-1;
108 
109       w = x * x + y * y;
110     } while(w >= 1 || w == 0);
111     w = sqrt(-2.0 * log(w) / w);
112 
113     buffer[i] = x * w + ( y * w )*I;
114   }
115 }
116 
117 /**
118  * Return a Generalized Pareto random number (double)
119  * Where the generalized pareto parameters are (like in MATLAB)
120  *  k: shape (-inf..inf) (xi for some authors)
121  *  sigma: scale (0..inf)
122  *  theta: location (-inf..inf) (mu for some authors)
123  */
bs_random_GPRND(double k,double sigma,double theta)124 double bs_random_GPRND(double k, double sigma, double theta){
125   double u = ( ((double)random()) / ((double)RAND_MAX)); //U(0,1) : uniformly distributed random number from 0 to 1
126   double r;
127   if ( fabs(k) < 0.005 ){ //effectively there is no difference in the shape of the distribution from k = 0
128     r = -log(u);
129   } else {
130     r = expm1(-k*log(u)) / k; // ( u^(-k) - 1 ) / k
131   }
132   r = theta + sigma*r;
133   return r;
134 }
135 
136 /**
137  * Draws a bit {0,1}
138  */
bs_random_bit()139 char bs_random_bit(){
140   return ( random() & 1 );
141 }
142 
143 /**
144  * Draws a number from a U[0,1]
145  */
bs_random_uniform()146 double bs_random_uniform(){
147   return ( ((double)random()) / ((double)RAND_MAX));
148 }
149 
150 /**
151  * Draws a number from a U[a,b] (both double)
152  */
bs_random_uniformR(double a,double b)153 double bs_random_uniformR(double a, double b){
154   double u = ( ((double)random()) / ((double)RAND_MAX));
155   u *=(b-a);
156   u +=a;
157   return u;
158 }
159 
160 /**
161  * Draws a number from a U[a,b] (both integer)
162  *  b > a
163  */
bs_random_uniformRi(int a,int b)164 int bs_random_uniformRi(int a, int b){
165   if ( b <= a )
166     return a; //safety feature
167 
168   int i_u;
169   while (1) {
170     double u = ( ((double)random()) / ((double)RAND_MAX)); //[0..1]
171     u *=(b+1-a); //[0.. (b+1-a)]
172     u +=a;       //[a..b+1]
173     i_u = floor(u); //[a,..,b+ups]
174     if (i_u <= b) //although extremely unlikely, we could get RAND_MAX out of the random generator and otherwise produce b+1
175       break;
176   }
177   return i_u;
178 }
179 
bs_random_uint32()180 uint32_t bs_random_uint32(){
181   return (uint32_t)random();
182 }
183