Fixing the randomSeed() function (when using analogRead)

(First post - hope this isn't already covered elsewhere...)

I was having a problem with randomSeed() - calling it like this:

randomSeed(analogRead(0));

Is very unrandom. However, in digging, it appears to be the fault of the analogRead(0).

My question - does anyone else have this problem, or is it just my Arduino?

So I put together a test program:

void setup()
{
  Serial.begin(9600);
  for (int i=0;i<256;++i)
  {
    Serial.print(analogRead(0));
    if (0==(i&0xF)) // for line breaking/formatting
      Serial.print("\n");
    Serial.print(" ");
  }
}
void loop()
{
}

Here’s some of my results:

450 448 448 449 449 447 447 448 448 446 446 447 446 445 444 445
445 443 443 444 444 442 442 443 442 441 441 442 441 440 440 440
440 439 439 440 439 438 438 439 438 437 437 438 437 436 436 437
435 434 435 435 434 433 434 434 433 432 432 433 432 431 431 432

As you can see, it's nowhere near the 0-1023 (10 bit) range expected.

To use, just run it for your Arduino – I’m very curious if everyone else has this very narrow range of values.

My reason for asking is that I solved the problem, but realized I don't know if anyone else has the same issue!

The whole solution (with explanation and code) is here:

http://www.utopiamechanicus.com/53/arduino-better-random-numbers/

Obviously, if random bias is not affecting your Arduino, then I've solved a non-existent problem - so I'd appreciate any feedback.

Thanks!

I was having a problem with randomSeed()

It doesn't look to me like the problem is in randomSeed. The problem was in the value that you not supplied to the randomSeed function.

So, at the very least, the thread title is wrong.

PaulS:
So, at the very least, the thread title is wrong.

I added to the title to remove any chance of ambiguity (I hope) - now I'm still hoping someone can tell me if the Arduino output from analogRead(0) is as unrandom as I'm getting on mine...

now I'm still hoping someone can tell me if the Arduino output from analogRead(0) is as unrandom as I'm getting on mine...

It probably depends on how long the antenna attached to analogue pin zero is.
And what sources there are nearby.

now I'm still hoping someone can tell me if the Arduino output from analogRead(0) is as unrandom as I'm getting on mine...

First what is wired to analog pin 0? If nothing is wired to it, what are your expectations of the range of values to be returned by reading the pin? If it's the full range of 0-1023 that you expect then you will be dissapointed.

The use of reading a unwired to analog input pin to use as a seed for random, is to just get a few bits of noise variation to start with, otherwise random will return identical numbers with every returned value (useful for some things). Reading a disconnected analog input pin will not return a completely 'random' value in the 0-1023 range.

Lefty

There's no way you'll get very random from reading an ADC as you've found out, but there is low-value noise there. If you look at the LSB for each of those values you get this

0001 1110 0001 0101 1110 0001 0110 1000 0110 1001 0110 1001 1011 0100 1001 0110

Put that together and you have something resembling two 32-bit random numbers (maybe). How about doing that 100 times and seeing just how random it is.


Rob

You will get something like:

unsigned long seed = 0;
for (int i=0; i<32; i++)
{
  seed = seed | ((analogRead(A0) & 0x01) << i);
}
randomSeed(seed);

If you don't have an analog line free to generate a seed you could use the internal temp sensor (A8, UNO) or from the internet see - http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1294239019 -

Put that together and you have something resembling two 32-bit random numbers (maybe). How about doing that 100 times and seeing just how random it is.

You will get something like:

That doesn't work very well either. Successive analogRead values on an unconnected pin or antenna pin have a strong tendency to return the same value. In addition, an unconnected pin or antenna pin is influenced by anything nearby including sinking pins, sourcing pins, switching pins (PWM is a strong influence), ground wires, power wires, non-incandescent light bulbs, and human hand.

Adding an antenna can actually make the problem worse. Small differences in antenna length can make a huge difference in the analogRead values.

The simple fact is that analogRead is a poor choice for initializing the random number generator.

Von Neuman had a simple way of removing random bit bias

Yes, but it does not turn non-random data into random data. If the values from analogRead do not have enough entropy or include "bigger" patterns, whitening is not going to change that fact.

In a nutshell, I decided to use the change between values – if the next number from analogRead() was different from the previous one, I counted it as a single ’1?, and if no change, I’d count it as a ’0?

Putting those two together is unbounded. Good of you to include a limit in bitOut. Unfortunately, that has the potential to make your code no different than "randomSeed(9);".

Are we making this all too theoretical? We are not trying to improve the quality of the random() function, but just rather trying to come up with a good enough seed value to insure that we can overcome the default nature of random() of always starting with the same default seed and therefore the same repeating random numbers are returned by the random() function.

Something as simple as having a setup sequence of serial "hit any key to start" and then using micros() to return a value to use as the seed would probably be just fine. However a more fully automatic starting seed would be advantageous for many applications.

Lets not guild the lilly, just find me a good enough starting random seed. :grin:

Lefty

I've been mulling over a potential source of truly random data that would be super low budget to implement. Something like a J-FET op-amp amplifying noise from a diode, or analogue read of the threshold (pin 6) of a free-running high frequency 555 oscillator. Is feels like something should be possible with maybe 6 parts.

Ideally there would be something as simple as a single reverse-biased emitter-base junction that anyone could set up with a transistor and a resistor.

I guess I have an electronics project.

My ideal hardware would be something that uses only one wire at best, or an I2C random chip to be read.

Something like the DS3640 - Mixed-signal and digital signal processing ICs | Analog Devices -
Key Features

  • 1024-Byte Nonimprinting Key Memory with High Speed Erase*
  • 64-Byte General-Purpose RAM (Not Cleared)*
  • RTC Watchdog Timer CPU Supervisor*
  • Four General-Purpose Tamper Detect Comparators with Associated Reference*
  • Three Tamper-Detect Logic Inputs*
  • On-Chip Programmable Temp Sensor*
    _ On-Chip Random Number Generator (RNG)_
  • Latching and Time Stamping of Tamper Events*
  • 3.0V to 3.6V Single Supply Operation*
  • BGA Package with No Horizontally-Exposed Leads*
  • Underwriters Laboratories (UL) Recognized*

more chips see - Mixed-signal and digital signal processing ICs | Analog Devices -

Never tried, don't know the price, but it would be fun to have one with an Arduino lib.

retrolefty:
Are we making this all too theoretical?

No. It is a question of "reliability". On some boards under some conditions, analogRead is a reasonable choice. It is reliable for that particular project.

But, on other boards or under other conditions, seeding code that makes use of analogRead boils down to "randomSeed(SOMECONSTANT)". Seeding the random number generator using analogRead, in general, is unreliable.

The only way I can reach that conclusion is by dumping what little theory I know into a whole lot of testing. So, at least some theory has to come into play so the technique can be proven to be generally reliable.

We are not trying to improve the quality of the random() function, but just rather trying to come up with a good enough seed value to insure that we can overcome the default nature of random() of always starting with the same default seed and therefore the same repeating random numbers are returned by the random() function.

I wholeheartedly agree (!) with a few additions...

• It must be reliable across all Arduino hardware

• It must be reliable for all projects

• It should not require any external hardware (extra hardware would ruin some projects)

• It should not make use of any I/O pins (some projects cannot spare the pin)

Something as simple as having a setup sequence of serial "hit any key to start" and then using micros() to return a value to use as the seed would probably be just fine.

That is an excellent choice for applications that interact with a human.

However a more fully automatic starting seed would be advantageous for many applications.

For those willing to add hardware, this is a great choice...
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1294239019/13#13

Lets not guild the lilly, just find me a good enough starting random seed. :grin:

Oh, I've given up on gilding anything. In every way shape and form AVR processors are extremely non-random. At this point I will definitely settle for "good enough"!

One more important item about randomSeed... This is from the Park-Miller paper...

This generator must be initialized by assigning seed a value between 1 and 2147483646.

Seeds outside that range cause random to behave erratically for a while.

That makes sense - 2147483647 is the largest number you can represent with 31 bits, so perhaps using 32 bits risks it being recognized as a signed long instead of an unsigned one, and doing internal calculations with (possibly) a negative number. I'll keep that in mind and only generate 31 bits maximum for any random number, so it's always the same value, whether stored in a long or unsigned long.

However, does this mean that 2147483647 and 0 are explicitly bad? If so, I'd need to fiddle with code to guarantee those two values can't appear - I suppose the easiest way would be to ( value & 0x7FFFFFFE ) | 2, so the last bit is always zero (so 2147483647 can't occur) and the second bit is always 1 (so 0 can never occur). However, including the high bit, that's 3 bits out of 32 lost, so if I can avoid that I'd prefer to...

Seeds outside that range cause random to behave erratically for a while

Well, call me old-fashioned, but isn't that exactly what you would want "random" to do? :smiley:

XD "Erratic" may have been a poor word choice.

erratically has many forms. Frozen to 0 would be erratically but not random ...

But I agee Awol, a random generator should accept all numbers as seed.

Or better, you want seed to accept a stream of bits of any length (ok multiple of 32) so it can reseed itself once and a while automagically ...

I'm surprised no one has mentioned the many places this exact line,

randomSeed(analogRead(0));

is mentioned in the Arduino reference and many examples. You can't fault someone for being confused when the documentation is not accurate.