0
$\begingroup$

I am using the rand() function in C to generate white noise in DSP processors, but its behavior varies depending on where it is called.

I have posted a question on Stack Overflow. Reference question Any technical assistance would be greatly appreciated.


The root cause for the behavior is found and the question Posted on stack overflow has been changed, but if any other insights on this will be helpful why rand is affected by MODE1 register ALU saturation bit setting.

I repeat everyone going through this question please have a look at the posted question link from above, where I have explained briefly.

$\endgroup$
6
  • $\begingroup$ There's some good C code for the Mersenne Twister. It's supposed to be a decent random number generator if your need is not cryptographic. I would think someone could make it into a good pseudo-gaussian random number generator. $\endgroup$ Commented Feb 20 at 12:50
  • $\begingroup$ @robertbristow-johnson in essence, very much what the mersenne_twister_engine in C++'s standard library does in conjuction with the normal_distribution shaper (note though, that while excellent, Mersenne twisters are very state-space intense and slow; they do fall out of favor for a lot of small-device implementations). I don't know your compiler suite of choice, but if you have GCC, and look into the (equivalent on your OS of) … $\endgroup$ Commented Feb 20 at 12:59
  • $\begingroup$ @robertbristow-johnson … /usr/include/c++/{VERSION}/bits/random.h , you will find the mersenne_twister_engine's method operator(), which gives you a random number. Its implementation is in …/bits/random.tcc ; look for _M_gen_rand(void) in that. that C++ is, as far as I can tell, "nearly valid C", when you replace the template<typename _UIntType… with a simple typedef uint64_t _UIntType (and remember that _M_x is just a classical C array containing the generator's state). $\endgroup$ Commented Feb 20 at 13:05
  • 1
    $\begingroup$ @MarcusMüller , I think the Mersenne Twister code in the wikipedia article (that I happened to write by severely simplifying the original code from the authors - I was in contact with the authors) is pretty efficient in time. It's still requires 624 words of 32 bits each, but each call is quite fast. Just 10 or so instructions. But the result is a uniform p.d.f. 32-bit unsigned integer. To make that into a good gaussian r.v. requires a little more work. $\endgroup$ Commented Feb 20 at 13:12
  • $\begingroup$ @robertbristow-johnson yes, exactly (the uniform PRNG is the fast part, even if the Mersenne Twister Algorithm even as nicely implemented as you have it there :) is still relatively slow compared to smaller-statespace congruental generators). Also, making good Gaussian PDF is hard; generators tend to either have overly strongly suppressed tails, or have problems with symmetry around 0 (which hurts, a lot), or they have a few values in the far tails that appear too often. So far, I've been coming back to the Box-Muller transform, as the Ziggurat algorithm needs a lot of computation, which… $\endgroup$ Commented Feb 20 at 13:33

2 Answers 2

8
$\begingroup$

C rand() is really a bad choice for a random number generator in DSP applications. It is not thread-safe (which is extensively documented), and the C standard makes no statement on the generator itself – it can be any algorithm, no matter how bad.

So, this is not surprising; as a matter of fact, my system's C library documentation (man 3 rand) even explicitly states this:

Do not use this function in applications intended to be portable when good randomness is needed. (Use random(3) instead.)

Now, I agree with the first part, and disagree with the parentheses – random() is better, but not great, either (their randomness leaves things to be desired, they have relatively short sequence length and on top, they are slow, in case of my C library. Your C library will probably be not any better).

Simply use a different random generator. If you're using C++¹, std::random has alternatives. But for portable C, Xoroshiro (code on the right half of the page) is a good family of generators both for integer and floating point generations. In GNU Radio, we use the Xoroshiro128+ algorithm in code where I extracted the state, so that one can have arbitrarily many parallel random generators in parallel (if you're using C++ distribution shapers, you can also use XOROSHIRO generator there).

A former student of mine has implemented Xoroshiro128+ in digital logic on an FPGA to generate fixed-point normally-distributed numbers² at 38 GS/s. This thing is plenty compact and fast enough (and the student was really good).

Another thing: you're doing srand(time(0)). That is not an appropriate seed. I know this has been appearing in examples probably since the 1970s, but it's just a really really bad idea, and I don't know why it has still survived. If you want reproducible random number generation (e.g. for testing, or for pseudorandom correlation sequences or such), seed deterministically (seed "4 was chosen by fair dice roll"); if you need truly random, almost certainly-different-every-time, then, well using the second as seed is about the worst thing you can choose (it being predictably the same for 1s, in which your computer can do many billion operations).

So, when seeding: If you're doing C++, your OS (or just the HAL) usually implements std::random_device, which you can use for getting a good random seed. If you don't have such amenities, figure out how your embedded device produces real random bits (it might, for example, just have a CPU register that contains a truly-random number when read). If you're running a unixoid embedded operating system (Linux, *BSD, QNX, …), you might just be able to read bytes out of /dev/random; on Windows, Android, iOS, Zephyr etc, there's operating system APIs to get random seeds.


¹ I mention C++ although your question says C because you're writing C for embedded, but are making use of one of the "fatter" libc features, so chances are you actually have a full C++ runtime at hand, by the way.

² which was necessary because we were testing things that might be sensitive to repetitive input, so the digital design-typical BERT tester PRNGs didn't cut it

$\endgroup$
1
  • 1
    $\begingroup$ Nice write-up!! $\endgroup$ Commented Feb 20 at 12:39
-1
$\begingroup$

Perhaps you could use a true or quantum-random source like a noise diode, together with a simple algorithm, to generate high quality random numbers. Whether such a method would work for you depends on your required sampling speed and other factors. However, it is a method I have used successfully to generate very high quality random numbers for various projects. And, with proper implementation, it can be quite fast.

$\endgroup$
1
  • $\begingroup$ I should add that the standard "C" psuedo-random number generator is terrible! There are much better ones, such as "Mersenne Twister". True quantum random number generators, when well designed, are best in terms of generating true random numbers $\endgroup$ Commented Nov 1 at 19:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.