File: random.cpp

package info (click to toggle)
satdump 1.2.2%2Bgb79af48-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 81,648 kB
  • sloc: cpp: 276,768; ansic: 164,598; lisp: 1,219; sh: 283; xml: 106; makefile: 7
file content (109 lines) | stat: -rw-r--r-- 3,318 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include "random.h"
#include <chrono>

namespace dsp
{
    Random::Random(unsigned int seed, int min_integer, int max_integer)
        : d_rng(), d_integer_dis(0, 1)
    {
        d_gauss_stored = false; // set gasdev (gauss distributed numbers) on calculation state

        // Setup Random number generators
        reseed(seed); // set seed for Random number generator
        set_integer_limits(min_integer, max_integer);
    }

    Random::~Random() {}

    /*
    * Seed is initialized with time if the given seed is 0. Otherwise the seed is taken
    * directly. Sets the seed for the Random number generator.
    */
    void Random::reseed(unsigned int seed)
    {
        d_seed = seed;
        if (d_seed == 0)
        {
            auto now = std::chrono::system_clock::now().time_since_epoch();
            auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
            d_rng.seed(ns);
        }
        else
        {
            d_rng.seed(d_seed);
        }
    }

    void Random::set_integer_limits(const int minimum, const int maximum)
    {
        // boost expects integer limits defined as [minimum, maximum] which is unintuitive.
        // use the expected half open interval behavior! [minimum, maximum)!
        d_integer_dis = std::uniform_int_distribution<>(minimum, maximum - 1);
    }

    /*!
    * Uniform Random integers in the range set by 'set_integer_limits' [min, max).
    */
    int Random::ran_int() { return d_integer_dis(d_rng); }

    /*
    * Returns uniformly distributed numbers in [0,1) taken from boost.Random using a Mersenne
    * twister
    */
    float Random::ran1() { return d_uniform(d_rng); }

    /*
    * Returns a normally distributed deviate with zero mean and variance 1.
    * Used is the Marsaglia polar method.
    * Every second call a number is stored because the transformation works only in pairs.
    * Otherwise half calculation is thrown away.
    */
    float Random::gasdev()
    {
        if (d_gauss_stored)
        { // just return the stored value if available
            d_gauss_stored = false;
            return d_gauss_value;
        }
        else
        { // generate a pair of gaussian distributed numbers
            float x, y, s;
            do
            {
                x = 2.0 * ran1() - 1.0;
                y = 2.0 * ran1() - 1.0;
                s = x * x + y * y;
            } while (s >= 1.0f || s == 0.0f);
            d_gauss_stored = true;
            d_gauss_value = x * sqrtf(-2.0 * logf(s) / s);
            return y * sqrtf(-2.0 * logf(s) / s);
        }
    }

    float Random::laplacian()
    {
        float z = ran1();
        if (z > 0.5f)
        {
            return -logf(2.0f * (1.0f - z));
        }
        return logf(2 * z);
    }
    /*
    * Copied from The KC7WW / OH2BNS Channel Simulator
    * FIXME Need to check how good this is at some point
    */
    // 5 => scratchy, 8 => Geiger
    float Random::impulse(float factor = 5)
    {
        float z = -1.41421356237309504880 * logf(ran1());
        if (fabsf(z) <= factor)
            return 0.0;
        else
            return z;
    }

    complex_t Random::rayleigh_complex() { return complex_t(gasdev(), gasdev()); }

    float Random::rayleigh() { return sqrtf(-2.0 * logf(ran1())); }
} // namespace libdsp