Random number generator using $dist_uniform in SystemVerilog - random

I am trying to generate a random number using the $dist_uniform using Quartus and ModelSim.
The relevant code section is as follows (within a loop):
rand= $dist_uniform(10,20,25);
rand_test=$random;
'rand' is always 20 while 'rand_test' is varied on every iteration.
Would appreciate any advice on the matter.
I have tried many variations of the $dist_uniform as well as other distributions as well - the only way I have succeeded to generate a random number is by the $random command.

The first argument to the $dist_uniform function should be an integer variable, not a constant. Refer to IEEE Std 1800-2017, section 20.15.2 Distribution functions.
$dist_uniform ( seed , start , end )
... the seed argument is an inout argument; that is, a value is passed
to the function, and a different value is returned.
This produces 10 random integers between 20 and 25:
module tb;
integer rand_test, seed;
initial begin
repeat (10) begin
rand_test = $dist_uniform(seed, 20, 25);
$display(rand_test);
end
end
endmodule
Also, rand is a SystemVerilog (IEEE Std 1800) keyword. Trying to assign to it should give you a compile error. Many simulators require you to explicitly enable SV features.

Your use of $dist_random has a constant seed, so it always returns the same random value. In SystemVerilog, you should be using $urandom_range(maximal, minval=0) instead of $dist_uniform(seed, start, end), as well as $urandom instead of $random Even if your design is in Verilog, these system function should still be available for use in your testbench.
The $urandom function in SystemVerilog have much better uniform distributions of values and offer much better random stability (the ability to reproduce the same series of random values for debugging stimulus).

Related

Ada random Integer in range of array length

It's a simple question, yet I can't find anything that could help me...
I want to create some random connection between graph nodes. To do this I want do two random indexes and then connect the nodes.
declare
type randRange is range 0..100000;
n1: randRange;
n2: randRange;
package Rand_Int is new ada.numerics.discrete_random(randRange);
use Rand_Int;
gen : Generator;
begin
n1 := random(gen) mod n; -- first node
n2 := random(gen) mod n;
I wanted to define the range with length of my array but I got errors. Still, it doesn't compile.
Also I can't perform modulo as n is natural.
75:15: "Generator" is not visible
75:15: multiple use clauses cause hiding
75:15: hidden declaration at a-nudira.ads:50, instance at line 73
75:15: hidden declaration at a-nuflra.ads:47
And I have no idea what these errors mean - obviously, something is wrong with my generator.
I would appreciate if someone showed me a proper way to do this simple thing.
As others have answered, the invisibility of Generator is due to you having several "use" clauses for packages all of which have a Generator. So you must specify "Rand_Int.Generator" to show that you want the Generator from the Rand_Int package.
The problem with the "non-static expression" happens because you try to define a new type randRange, and that means the compiler has to decide how many bits it needs to use for each value of the type, and for that the type must have compile-time, i.e. static, bounds. You can instead define it as a subtype:
subtype randRange is Natural range 0 .. n-1;
and then the compiler knows that it can use the same number of bits as it uses for the Natural type. (I assume here that "n" is an Integer, or Natural or Positive; otherwise, use whatever type "n" is.)
Using a subtype should also resolve the problem with the "expected type".
You don't show us the whole code neccessary to reproduce the errors, but the error messages suggest you have another use clause somewhere, a use Ada.Numerics.Float_Random;. Either remove that, or specify which generator you want, ie. gen : Rand_Int.Generator;.
As for mod, you should specify the exact range you want when instantiating Discrete_Random instead:
type randRange is 0..n-1; -- but why start at 0? A list of nodes is better decribed with 1..n
package Rand_Int is new ada.numerics.discrete_random(randRange);
Now, there's no need for mod
The error messages you mention have to do with concept of visibility in Ada, which differs from most other languages. Understanding visibility is key to understanding Ada. I recommend that beginners avoid use <package> in order to avoid the visibility issues involved with such use clauses. As you gain experience with the language you can experiment with using common pkgs such as Ada.Text_IO.
As you seem to come from a language in which arrays have to have integer indices starting from zero, I recommend Ada Distilled, which does an excellent job of describing visibility in Ada. It is ISO/IEC 8652:2007, but you should have no difficulty picking up Ada-12 from that basis.
If you're interested in the issues involved in obtaining a random integer value in a subrange of an RNG's result range, or from a floating-point random value, you can look at PragmARC.Randomness.Real_Ranges and PragmARC.Randomness.U32_Ranges in the PragmAda Reusable Components.

urandom_range(), urandom(), random() in verilog

I am confused between these three functions and I was wondering for some explanation. If I set the range how do I make the range exclusive or inclusive? Are the ranges inclusive or exclusive if I don't specify the range?
In addition to the answer from #dave_59, there are other important differences:
i) $random returns a signed 32-bit integer; $urandom and $urandom_range return unsigned 32-bit integers.
ii) The random number generator for $random is specified in IEEE Std 1800-2012. With the same seed you will get exactly the same sequence of random numbers in any SystemVerilog simulator. That is not the case for $urandom and $urandom_range, where the design of the random number generator is up to the EDA vendor.
iii) Each thread has its own random number generator for $urandom and $urandom_range, whereas there is only one random number generator for $random shared between all threads (ie only one for the entire simulation). This is really important, because having separate random number generators for each thread helps you simulation improve a property called random stability. Suppose you are using a random number generator to generate random stimulus. Suppose you find a bug and fix it. This could easily change the order in which threads (ie initial and always blocks) are executed. If that change changed the order in which random numbers were generated then you would never know whether the bug had gone away because you'd fixed it or because the stimulus has changed. If you have a random number generator for each thread then your testbench is far less vulnerable to such an effect - you can be far more sure that the bug has disappeared because you fixed it. That property is called random stability.
So, As #dave_59 says, you should only be using $urandom and $urandom_range.
You should only be using $urandom and $urandom_range. These two functions provide better quality random numbers and better seed initialization and stability than $random. The range specified by $urandom_range is always inclusive.
Although $random generates the exact same sequence of random numbers for each call, it is extremely difficult to keep the same call ordering as soon as any change is made to the design or testbench. Even more difficult when multiple threads are concurrently generating random numbers.

sas treatment of seed when generating random distributions

I needed to generate a poisson distribution in excel and found a method (Inverse Transform Method)
did it in excel and then in sas (just for fun, so I do not need a quick answer) to compare with the ranpoi sas function.
Here my code (which works):
data Poisson(keep=mean Poisson PoissonSas);
mean=0.2;
confronta=exp(-mean);
do obs=1 to 100;
found=0;
Poisson=0;
ranuni=1;
do until(found=1);
ranuni=ranuni*ranuni(12547);
if ranuni<confronta then found=1;
else Poisson=Poisson+1;
end;
PoissonSas=ranpoi(012584,mean);
output;
end;
run;
proc means data=Poisson(drop=mean);run;
So I initialized the seed in both random functions to replicate results.
The strange thing is that I get different results depending on whether I submit the data step with both methods or only one of them (commenting the other), but the same results over and over for each type of submission.
I expected the same results always! Why this is not so?
(I am using sas 9.3)
Thanks!
It looks like SAS is interleaving the calls to the PRNGs as a single stream. Pseudo-random numbers are a sequence of values that are actually deterministic. If you seed and use the sequence in one algorithm, you'll get the same results every time for that algorithm. If you use the sequence alternating between two or more algorithms, the set of algorithms will always yield the same set of results (which seems to be the case for you), but the results for a given algorithm will be different because some of the underlying PRNs it was drawing before are now being used by the other algorithms. This is at the core of the synchronization requirement when using so-called variance reduction techniques based on common random numbers. In general, if you want identical results the solution is to have multiple instances of your PRNG, one for each "source" of randomness in your program, and to seed the multiple sources independently of each other but identically across runs. It looks like you tried to do this, but SAS doesn't behave the way you think it does. According to their documentation, it appears that they produce a single PRN stream based on the first seed entry in your code! This is a subset of one of their examples:
/* This DATA step calls the RANUNI and the RANNOR functions */
/* and produces a single stream of random numbers based on */
/* a seed value of 7. */
data d;
d = ranuni (7); f = ' '; output;
d = ranuni (8); f = ' '; output;
d = rannor (9); f = 'n'; output;
/* they actually have more... */
run;
By the way, your Poisson algorithm is not generally regarded as an inverse transform algorithm. Inversion is 1-to-1, i.e., a single input uniform produces a single random variable. The loop you're performing is actually doing acceptance/rejection, and you use a variable number of uniforms to come up with each Poisson value.
PJS's answer is essentially correct, but a few clarifications.
SAS does indeed use a single seed when you do it the way you did; all of what I'd call 'primitive' random functions work off of one PRNG stream, and only the first seed matters (and only matters the first time it's encountered).
However, RANPOI is a little different - probably because of how SAS creates poissons. It's not made clear in the documentation, but it appears that it uses up two random numbers (not sure if it's always two, or just coincidence). See the following test:
data test;
U=ranuni(7);
P=ranpoi(8,100);
put u= p=;
run;
data test2;
p=ranpoi(8,100);
u=ranuni(7);
put u= p=;
run;
data test3;
u=ranuni(8);
p=ranuni(7);
put u= p=;=
run;
data test4;
u=ranuni(7);
p=ranuni(8);
put u= p=;
run;
data test5;
do _t = 1 to 5;
u=ranuni(8);
put u=;
end;
run;
Now, in test4, we see the first two ranuni's when starting with seed 7, and indeed the first one matches the first one from test. However, test3 has the first two starting with seed 8, and the second one does not match the one from test2! test5 shows that in fact the third matches, meaning ranpoi in test2 used up 2 numbers from the stream.
In any event, if you want to change the seed midstream, you have two options.
One is to use CALL RANPOI (and CALL RANUNI), which allow you to store the seed in a variable. Two is to use RAND function, which works with CALL STREAMINIT to set seeds whenever you want to. The RAND function is considered 'better' than the more primitive RANPOI and such - it uses a better PRNG algorithm.

How to output array elements in random order using VHDL

I have an array of 10 elements. How do I output these in random order without repeating.
For a testbench, use the OSVVM random library to generate random indexes into your array. Or you could shuffle it (using the Fischer-Yates Algorithm in concert with the random library).
If it's something you need to synthesize, then put the array into a RAM block, and generate random addresses (for example using a linear feedback shift register).
Be aware that none of these is properly random, only pseudo-random. If you're attempting anything remotely cryptographic, they are unlikely to be what your want.
For testbenches, OSVVM's RandomPkg makes this easy.
library osvvm ;
use osvvm.RandomPkg.all ;
...
RandProc : process
variable RV : RandomPtype ;
variable IndexVals : integer_vector(0 to 9) := (others => integer'low) ;
begin
for i in IndexVals'range loop
-- min max ExcludeList
IndexVals(i) := RV.RandInt( 0, 9, IndexVals) ;
end loop ;
The problem gets more interesting if successive randomly generated permutations of 10 elements need to be different from the previous one. For that I would use the coverage model. Although, 10 is around the maximum number of permutations I would want to do this way though as there are n! permutations and the coverage model will require storage for each permutation generated.
A good way to get close to randomness is by using a linear feedback shift register.
http://en.wikipedia.org/wiki/Linear_feedback_shift_register
If this is for simulation only, you can use the uniform procedure from ieee.math_real to get a real number between 0 and 1, and scale it to the index range of your array.

Integer to Binary Conversion in Simulink

This might look a repetition to my earlier question. But I think its not.
I am looking for a technique to convert the signal in the Decimal format to binary format.
I intend to use the Simulink blocks in the Xilinx Library to convert decimal to binary format.
So if the input is 3, the expected output should in 11( 2 Clock Cycles). I am looking for the output to be obtained serially.
Please suggest me how to do it or any pointers in the internet would be helpful.
Thanks
You are correct, what you need is the parallel to serial block from system generator.
It is described in this document:
http://www.xilinx.com/support/documentation/sw_manuals/xilinx13_1/sysgen_ref.pdf
This block is a rate changing block. Check the mentions of the parallel to serial block in these documents for further descriptions:
http://www.xilinx.com/support/documentation/sw_manuals/xilinx13_1/sysgen_gs.pdf
http://www.xilinx.com/support/documentation/sw_manuals/xilinx13_1/sysgen_user.pdf
Use a normal constant block with a Matlab variable in it, this already gives the output in "normal" binary (assuming you set the properties on it to be unsigned and the binary point at 0.
Then you need to write a small serialiser block, which takes that input, latches it into a shift register and then shifts the register once per clock cycle with the bit that "falls off the end" becoming your output bit. Depending on which way your shift, you can make it come MSB first of LSB first.
You'll have to build the shift register out of ordinary registers and a mux before each one to select whether you are doing a parallel load or shifting. (This is the sort of thing which is a couple of lines of code in VHDL, but a right faff in graphics).
If you have to increase the serial rate, you need to clock it from a faster clock - you could use a DCM to generate this.
Matlab has a dec2bin function that will convert from a decimal number to a binary string. So, for example dec2bin(3) would return 11.
There's also a corresponding bin2dec which takes a binary string and converts to a decimal number, so that bin2dec('11') would return 3.
If you're wanting to convert a non-integer decimal number to a binary string, you'll first want to determine what's the smallest binary place you want to represent, and then do a little bit of pre- and post-processing, combined with dec2bin to get the results you're looking for. So, if the smallest binary place you want is the 1/512th place (or 2^-9), then you could do the following (where binPrecision equals 1/512):
function result = myDec2Bin(decNum, binPrecision)
isNegative=(decNum < 0);
intPart=floor(abs(decNum));
binaryIntPart=dec2bin(intPart);
fracPart=abs(decNum)-intPart;
scaledFracPart=round(fracPart / binPrecision);
scaledBinRep=dec2bin(scaledFracPart);
temp=num2str(10^log2(1/binPrecision)+str2num(scaledBinRep),'%d');
result=[binaryIntPart,'.',temp(2:end)];
if isNegative
result=['-',result];
end
end
The result of myDec2Bin(0.256, 1/512) would then be 0.010000011, and the result of myDec2Bin(-0.984, 1/512) would be -0.111111000. (Note that the output is a string.)

Resources