Boris
Boris

Reputation: 8941

Algorithm for "smooth" random numbers

Could anyone give me a hint on how to generate "smooth" random numbers? Here's what I mean by smooth:

The random numbers shall be used in a game, e.g. for wind direction and strength (does anyone remember goood old "Worms"?). Of course setting random numbers for those values every second or so would look awfully choppy. I would rather have some kind of smooth oscillation in a given value range. Sort of like a sine wave but much more random.

Does anyone get what I'm after? ;-) Any ideas on how to achieve this kind of behavior would be appreciated.

Upvotes: 12

Views: 7116

Answers (3)

David Sánchez
David Sánchez

Reputation: 606

I created a new version of a smooth random number. The idea is that our random number is going to be within limits = [average - oscillation, average + oscillation], and will change everytime [-varianciance, +variance].

But, if it reaches the limits, our variance is going to be reduce.

E.g. numbers from [0, 100], with variance of 10. If the current value = 8, then the variance will be [0, 18]

python code:

def calculate_smooth_random(current_value, average, oscillation, variance):
    max_value = average + oscillation
    min_value = average - oscillation

    max_limit = min(max_value, current_value + variance)
    min_limit = max(min_value, current_value - variance)
    total_variance = max_limit - min_limit

    current_value = min_limit + random.random() * total_variance

    print("current_value: {}".format(current_value))
    return current_value

Image for distribution with values: average: 20 oscillation: 10 variance: 5

enter image description here

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 881703

If you want the delta (change) to be small, just generate a small random number for the delta.

For example, instead of:

windspeed = random (100)                # 0 thru 99 inclusive

use something like:

windspeed = windspeed - 4 + random (9)  # -4 + 0..8 gives -4..4
if   windspeed > 99: windspeed = 99
elif windspeed <  0: windspeed =  0

That way, your wind speed is still kept within the required bounds and it only ever changes gradually.

This will work for absolute values like speed, and also for direction if the thing you're changing gradually is the angle from a fixed direction.

It can pretty well be used for any measurement.


Alternatively, if you want to ensure that the windspeed changes with a possibly large delta, but slowly, you can generate your target windspeed as you currently do but move gradually toward it:

windspeed = 50
target = windspeed
while true:
    # Only set new target if previous target reached.

    if target == windspeed:
        target = random (100)
    
    # Move gradually toward target.

    if target > windspeed:
        windspeed = windspeed + max (random (4) + 1, target - windspeed)
    else:
        windspeed = windspeed - max (random (4) + 1, target - windspeed)

    sleep (1)

Upvotes: 9

Will Squire
Will Squire

Reputation: 6595

Perlin (or better simplex) noise would be the first method that comes to mind when generating smoothed noise. It returns a number between 1 and -1, which will add or subtract from the current value. You can multiple that to make it seem less subtle or better yet... make the lowest wind value -1 and highest wind value 1.

Then simply have a seeder as a counter (1,2,3... etc) as the perlin/simplex input keep the values 'smooth'.

Upvotes: 4

Related Questions