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