How do I filter a RNG output to produce biased numbers?

Hi all,
I am using a random number generator to determine when the Arduino should emit a pulse.
Random means that the frequency distribution of pulses in the output is approximately equal. There's as much 1Hz content in the output as there is 1000Hz content in the output: pulses happen once a second just as much as they do a thousand times a second.
I want the frequency distribution to roll off evenly, with a flat NdB/octave slope. I would also like to be able to bandpass filter it, so that the pulses tend to happen at 500Hz but also happen quite frequently at other times as well. Is this possible?

You need to rethink your basic premise, methinks. You can produce a 1KHz tone for one second, but you can't produce a 1Hz tone for 1/1000th of a second, yes?

Can you re-define your requirements for us? Are you trying to produce white noise?

BTW, what is RNG?

suppose your RNG generates between 1 and 1000 you can feed that number to a function that reformats the distribution.

e.g.

float x = random(1,1000);
float y = 1 + 100*exp(x/500); // 101 .. 739
float z = exp(10/x); // 22000 .. 1

to get another distribution.

float x = random(1,1000);
float y = x + (x/2?10*sin(x):1000/x; // usefulness of this one has to be investigated :slight_smile:

get the idea?

RNG - Random Number Generator

I'm not sure what you intend the bandpass filter to do, but the rest of what you're describing is achievable by applying a transform to the uniform random number in your input domain to convert it into your output domain. Conceptually, if you were to plot the input and output values of that transform then the slope of the plot at a given output value would give you the probability density at that output value - if you see what I mean?

robtillaart:
suppose your RNG generates between 1 and 1000 you can feed that number to a function that reformats the distribution.

e.g.

float x = random(1,1000);
float y = 1 + 100*exp(x/500); // 101 .. 739
float z = exp(10/x); // 22000 .. 1

to get another distribution.

float x = random(1,1000);
float y = x + (x/2?10*sin(x):1000/x; // usefulness of this one has to be investigated :slight_smile:

get the idea?

Clever, but I don't know how to express my desired filter as such a function.

Let me take a guess at it.

Assuming that
float x = random(1,1000);
generates an even frequency distribution from some start frequency f_start to f_end = 1 / (pulse duration)
for 1000 possible frequencies between f_start and f_end

the probability of a given frequency appearing in the output filtered through
float z = exp(10/x)
requires first realizing that both z and x give the period associated with a given pulse (actually, period - pulse duration, but assuming pulse duration is negligible for the moment)

thus z_frequency = 1 / ( exp(10/x) )

now the probability of any given value of x coming up is 1/1000

the probability of any value of z_freq coming up is also 1/1000
however this is now a question of density
does z_freq mean that, for a given pulse, the output value z_freq is more likely to lie between some range z_freq_0 to z_freq_1 than it is for other ranges?

where dz/dx = 0, a change in x produces no change in z
therefore the probability of a given value z_freq appearing in the output is 1 if x happens to come up within a range where dz/dx=0 (and where z_freq(x) = that given value)

where dz/dx = 1, a change in x produces equal change in z
therefore the probability of a given value of z_freq appearing in the output is 1/1000 if x happens to come up within a range where dz/dx = 1

where dz/dx = infinity, a change in x produces an infinitely large change in z
therefore the probability of a given value of z_freq appearing in the output is 0 if x comes up where dz/dx = infinity

now how to get from there to a filter function? need to say, how does the probability of a frequency appearing in the output change as a function of x given some function z_freq()

okay, it's probably going to involve differentiating z_freq()
the points (1, 0), (1/1000, 1), (0, infinity) and suggest a function of the form y = exp(-Cx)
so probability = exp (-C * dz/dx )

well the only data point we have to go on of any substance is (1/1000, 1)
backsolving 1/1000 = exp ( -C )
ln(1/1000) = -6.907 --> C = 6.907

now we have to differentiate z_freq
z_freq = 1 / ( exp(10/x) )

crap, I forgot how to do this

either way, we have a filter admittance function, I think
admittance = exp ( 6.907 * dz_freq/dt)

right, now say my admittance function should have a negative slope of 10dB/octave
that's 10dB / ( (freq_0 * 10) / freq_0 )
or 10dB/10
or crap, I just realized I have no idea how to convert that into a slope function... it must be nonlinear...

whatever, keep admittance abstract

admittance(x) = exp (6.907 * dz_freq/dx)
ln( admittance(x) ) / 6.907 = dz_freq/dx
z_freq = integral of [ ln( admittance(x) ) / 6.907 )
or generalizing
z = 1 / ( integral of [ ln( admittance(x) ) / (ln( 1 / number of possible values for the RNG ) ]

Is that right?

PeterH:
I'm not sure what you intend the bandpass filter to do, but the rest of what you're describing is achievable by applying a transform to the uniform random number in your input domain to convert it into your output domain. Conceptually, if you were to plot the input and output values of that transform then the slope of the plot at a given output value would give you the probability density at that output value - if you see what I mean?

Wait, is it really that simple? I just spent a page working out that it has to be fed through an exponent... no, I have no formal education in probability stuff. I just want to be able to tell my Arduino to stop putting out a pulse at N Hz rep rate and start putting it out such that the frequency distribution over some period of time fits that of pink noise (even output power per octave, filter slope of -10dB/octave) or of bandpass filtered pink noise.