Pseudo random number and animal behavior

I am looking for a way to generate a pseudo random number say between 0-100 but the catch is that I want the number generated to verge toward the higher end (100) the longer an input is set. I still want the occasional low number but the frequency of lower-ish numbers will diminish as time progresses. I am trying to mimic fright response of grazing animals.

Any thoughts?

Thanks
Todd

Well it is not a random number then is it.
What you have to do is to model the probability distribution you want to start with and what you want to end up at and then interpolate between the two. You need to generate a random number based on the current distribution at any time.
One way of generating this is shown here:-
http://code.activestate.com/recipes/577264-random-numbers-with-arbitrary-probability-distribu/

However, I don't think this will result in the simulation you actually want. You are better off writing the equations for that simulation with known controllable inputs.

I'm guessing you won't like it but this paper looks like it points the direction to the "right" answer:

https://learning.stat.purdue.edu/wiki/_media/courses/sp2012/598z/rvgen.pdf

Basically, what you are trying to do is generate a random variable with arbitrary distribution function, one which can be parameterized on a "knob" (how long your input has been set).

There are ways to fake it. For example, if you generate two random numbers from 0-100, add them up, you will get numbers that range from 0-200, but they won't be uniformly distributed: their sum will be more likely to be near 100 than 0 or 200. If you add three random numbers, four random numbers, etc. etc. you will start to get a normal (Gaussian) distribution.

Say you generate 10 random numbers from 0-100, and add them up. The range is 0 to 1000, but they will clump around 500. You reject any sum of 10 numbers that is bigger than 500 (you just repeat the process and generate 10 new numbers). Then, you divide by 5. You will have an overall number in the range 0-100 but it will be more likely to be near 100 than near 0.

--
The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, speaker, microphone, light sensor, potentiometer, pushbuttons

Both of the above links will help, but to do what you want correctly, you will need to do some math. Essentially you need to determine/define th cummulative distribution function for the probability distribution you want–and how it will change according to you input.

Given a CDF, getting the correct probability from an uniform distribution is straight forward.

If the above is too much, you can ‘wing’ it by using the following trick.

byte weights[100];

int sum_weights()
{
   int retVal=0;
  for (int i=0; i<100; i++)
    retVal += weights[i];
}

byte newrnd(int basic_rnd)
{
  int tmp=0;
  int retVal
  for (int i=0; i<100; i++)
    if (tmp < basic_rnd) 
      tmp += weights[i];
    else
      retVal = i;
  return(retVal); 
}

void setup()
{
  for (int indx=0; indx<100; indx++)
    weights[indx] = 1;
}

loop
{
   int rVal, totWgt;
   // adjust weight array based on inputs.
   // Return a random number with the correct distribution
   totWgt = sum_weights();
   rVal = newrnd(random(totWgt))
}

By incrementing the 1’s in the numbers you want to improve the odds of you will adjust the probability of those values being returned. So for instance if you wanted the values from 50-99 to be twice as likely as the values 0-49, you would place the number 2 in the array for indices 50-99.

You can generate pseudo-random numbers with a normal distribution using a Box-Muller algorithm. Below is a function I’m using as part of a fake data generation project. This one is written to use doubles, which on Arduino are just the same as floats. With this, you can then parameterize where you want your mean and stdev to fall, then generate PRNG data with that distribution:

/* generate a pair of normally distributed random numbers
 * using a Box-Muller transformation. The mean is 0 -- numbers
 * are equally likely to be + or -.  The required stdev is
 * given in 'sigma'.  Either result pointers can be NULL, if
 * you want just one number.
 */
void box_muller(double sigma, double *r1, double *r2)
{
  double
     u1, u2,
     v1, v2, s,
     z1, z2;

  for (;;) {

     /* get two uniform random numbers from 0 to .999...
      */
     u1 = (float) random() / ((float) RAND_MAX + 1);
     u2 = (float) random() / ((float) RAND_MAX + 1);


     v1 = 2.0L*u1 - 1.0L;
     v2 = 2.0L*u2 - 1.0L;
     s = v1 * v1 + v2 * v2;

     if (s <= 1.0L && s != 0.0L)
        break;

  }

  z1 = sqrt (-2.0L * log(s) /  s) * v1;
  z2 = sqrt (-2.0L * log(s) / s) * v2;

  if (r1 != NULL) *r1 = (z1*sigma);
  if (r2 != NULL) *r2 = (z2*sigma);

  return;
}

YES! I think the the Box-Muller transformation is just what I need. I knew that someone had already tackled this problem. Thank you.

Todd

gardner:
You can generate pseudo-random numbers with a normal distribution using a Box-Muller algorithm. Below is a function I’m using as part of a fake data generation project. This one is written to use doubles, which on Arduino are just the same as floats. With this, you can then parameterize where you want your mean and stdev to fall, then generate PRNG data with that distribution:

Hello!
I am new to programming and I do not understand how I can call this function. If it is possible a simple example of a complete sketch, please.

I got it!

void box_muller(double sigma, double *r1, double *r2);


void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0));
}

void loop(){
  double r1, r2;
  box_muller(2, &r1, &r2);
  Serial.print(r1);
  Serial.print("; "); 
  Serial.println(r2); 
  delay(100);
}


/* generate a pair of normally distributed random numbers
* using a Box-Muller transformation. The mean is 0 -- numbers
* are equally likely to be + or -.  The required stdev is
* given in 'sigma'.  Either result pointers can be NULL, if
* you want just one number.
*/
void box_muller(double sigma, double *r1, double *r2)
{
  double
     u1, u2,
     v1, v2, s,
     z1, z2;

  for (;;) {

     /* get two uniform random numbers from 0 to .999...
      */
     u1 = (float) random(RAND_MAX) / ((float) RAND_MAX + 1);
     u2 = (float) random(RAND_MAX) / ((float) RAND_MAX + 1);


     v1 = 2.0L*u1 - 1.0L;
     v2 = 2.0L*u2 - 1.0L;
     s = v1 * v1 + v2 * v2;

     if (s <= 1.0L && s != 0.0L)
        break;

  }

  z1 = sqrt (-2.0L * log(s) /  s) * v1;
  z2 = sqrt (-2.0L * log(s) / s) * v2;

  if (r1 != NULL) *r1 = (z1*sigma);
  if (r2 != NULL) *r2 = (z2*sigma);

  return;
}

The code presented here is not the box-muller code, but the more efficient "Marsaglia polar method" Marsaglia polar method - Wikipedia

It is working quite well for simulated Normal distributions.

But what I really need is an equally simple way of generating Poisson distributions. I want to simulate Geiger counters, and radioactive decay is described with Poisson.

While the two types of distributions are almost the same from a mean of about 10 when you just take your eyes as tools to compare, they are significantly different at small means - most relevant: Poisson can't have negative numbers!

I'm now just cutting off negative numbers from the normal dist, but it is kind of awkward.

Can anybody help with Poisson distributions for an ESP32?