Random command strange results

Hey folks,

I'm trying to write a program to randomnly flash 16 LEDs one at a time, each time using one of 4 random colours with a random delay between each flash. The idea is to simulate shell flashes behind a model of a WWI trench.
The 4 colours are achieved by 12 potentiometers in groups of 3 (RGB), connected to A.0-A.3 (PNP transistors). The low sides are all connected to A.4, B.0-7, C.0-6. There's also a potentiometer connected to C.7 which adds an element of manual control to the flashing frequency.

Code:
init:    {

symbol retrievedDelayValue = b6
symbol retrievedLedValue = b7
symbol flashRate = b5
symbol pauseTime = w4
symbol i = b54
symbol highSide = b4

    let dirsC = %11101111
    let dirsB = 255
    let dirsA = 255
    
    let pinsa = 15
    let pinsb = 0
    let pinsc = 0
    
    w0 = 1   
    for i = 0 to 15
        pinsB = b0
        pinsC = b1
        gosub simu
        w0 = w0 << 1
    next i
    pinsB = 0
    pinsC = 0
    high a.4
    gosub simu
    low a.4
    }
main:    {

pinsA = 15

random w3
call readspeed
b7 = b7 // 15

pause w5

call maths

call play0

goto main
}
end

readSpeed:    {

readadc C.7, flashRate
'flashrate = flashrate rev 8            'Invert speed controller direction (optional)
flashRate = flashRate / 2
if flashRate = 0 then
flashRate = 1
end if

w5 = b6 + 100
w5 = w5 * flashRate

return    }

play0:    {
    call setLEDs
    pause 6
    call clearLEDs
    pause 3
    call setLEDs
    pause 50
    call clearLEDs
    pause 5
    call setLEDs
    pause 20
    call clearLEDs
    pause 5   
    call setLEDs
    pause 15
    call clearLEDs
    pause 5
    call setLEDs
    pause 10
    call clearLEDs
    pause 5
    call setLEDs
    pause 10
    call clearLEDs
    pause 8
    call setLEDs
    pause 10
    call clearLEDs
    pause 7
    call setLEDs
    pause 7
    call clearLEDs
    pause 9
    call setLEDs
    pause 5
    call clearLEDs
    pause 10
    call setLEDs
    pause 4
    call clearLEDs
    pause 11
    call setLEDs
    pause 3
    call clearLEDs
    pause 15
    call setLEDs
    pause 1
    call clearLEDs
    pause 20
    call setLEDs
    pause 1
    call clearLEDs
return    }

setLEDs:    {
    pinsB = b0
    pinsC = b1
    pinsA = b2
return    }

clearLEDs:    {
    pinsB = 0
    pinsC = 0
    low a.4
return    }

simu:    {
    low a.0
    pause 100
    toggle a.0
    toggle a.1
    pause 100
    toggle a.1
    toggle a.2
    pause 100
    toggle a.2
    toggle a.3
    pause 100
    high a.3
return    }

maths:    {
    w0 = 0
    w1 = %0000000000001111
    
    w0 = dcd b7
    bit20 = bit15
    bit15 = bit14
    bit14 = bit13
    bit13 = 0
    
    b4 = b7 // 4
    select b4   
case 0
    clearbit b2, 0
case 1
    clearbit b2, 1
case 2
    clearbit b2, 2
case 3
    clearbit b2, 3
endselect
    return    }
Notes: chip is a PICAXE-28X2 running at stock, internal frequency.
simu is just a startup test for the LEDs - useful for fault-finding :)
play0 is the PWM simulation to allow dimming of the LEDs

The problem I'm having is that line 35: random w3 is being a little funny: it seems to increment instead of being in any way random. When I've tested it, it's started at 2, and incrementing upwards at random intervals. Even seeding w3 with 0 or the timer value didn't alter this behaviour much.

Is there a problem with my implementation of random incorrect, or is there a fundamental problem here?
 

Aries

New Member
There's probably a bit more to this ...
If you start up a Picaxe and immediately use the timer value as a seed, it is virtually zero. AllyCat has explained before how the pseudo-random generator works. Roughly speaking, if w3 is your seed, then next value will be w3*2 [+1] where the [+1] occurs depending on the values of some bits in the middle of the word. So, if you start with (something close to) zero, you will get something like 0,2,5,11,23. It's only when the numbers get big enough that you start to see the random behaviour. Also - if my glance at your code is correct - you are using b7 to determine what happens. b7 = b7//15 only gives 15 (0 to 14) different values which is not enough if you want 16 LEDs to operate. Instead, you should use b7 = b7//16.
 
There's probably a bit more to this ...
If you start up a Picaxe and immediately use the timer value as a seed, it is virtually zero. AllyCat has explained before how the pseudo-random generator works. Roughly speaking, if w3 is your seed, then next value will be w3*2 [+1] where the [+1] occurs depending on the values of some bits in the middle of the word. So, if you start with (something close to) zero, you will get something like 0,2,5,11,23. It's only when the numbers get big enough that you start to see the random behaviour.
So in theory, if I pre-seeded w3 with an arbitrary number, somewhere in the 10,000 - 60,000 range during initialisation, that should result in "normal" behaviour?

Also - if my glance at your code is correct - you are using b7 to determine what happens. b7 = b7//15 only gives 15 (0 to 14) different values which is not enough if you want 16 LEDs to operate. Instead, you should use b7 = b7//16.
Erm... oopsie... :ROFLMAO:

Technical, given what Aries has said, would that line still be a problem? I've replaced the variable for the result of that calculation with b12 for now anyway, so that w3 never gets altered except by the RNG
 
Update: I tried pre-seeding w3 with 35634 during initialisation (random number from my head), and that seems to have worked. To add an extra layer of randomisation, I've also tried taking the ADC value from the potentiometer and multiplying it by 255 - I'll see how that works tonight on the hardware :)

Also noticed that I mixed up C.7 and C.4 during DIRS initialisation and the maths subprocedure...
 
Last edited:

Aries

New Member
Just one other thing about the pseudo-random generation ...
The routine generates all numbers between 1 and 65535 (never zero) so, wherever you start, sooner or later you will get back to a small number and you will see your problem recur. As long as you don't go on too long you may be all right. Otherwise you may have to trap small seeds and reset to something more to your liking.
 
Just one other thing about the pseudo-random generation ...
The routine generates all numbers between 1 and 65535 (never zero) so, wherever you start, sooner or later you will get back to a small number and you will see your problem recur. As long as you don't go on too long you may be all right. Otherwise you may have to trap small seeds and reset to something more to your liking.
That's a fair point... perhaps just trap any results below 10,000 and multiply by 10/100/1000, whichever would be required to bring the result back above 10,000 - cheers for that point!
 
Code:
if w3 < 10000 then            'The RNG uses the previous result (w3) as the seed for the next generation.
    if w3 < 1000 then            'To prevent low value seeds causing RNG problems, this procedure ensures the seed is always at or above 10,000.
        if w3 < 100 then
            if w3 < 10 then
                w3 = w3 * 10000
            else
                w3 = w3 * 1000
            end if
        else
            w3 = w3 * 100
        end if
    else
        w3 = w3 * 10
    end if
end if
 
Or perhaps just: DO WHILE W3 < 1000 : RANDOM W3: LOOP

Or "< 10000"
That would probably take longer than my plan though... purely because as we've seen, if the number were really low it would take a while for a random number to "grow" again.

Perhaps something similar, however:

Code:
do while w3 < 10000
    w3 * 10
loop
 

hippy

Technical Support
Staff member
I am not convinced low seed values are particularly a problem. By limiting the seed value all you are doing is limiting the range of numbers which will be generated and therefore limiting randomness, just creating a different pattern you will end up locked into.

I would suggest not worrying too much about making things 'more random', but get what you have working, identify what problems there may be, if any, then figure out how they may be best fixed.
 
sorry for the late reply - events overtook me and I had to press the program into use. On the plus side, it performed perfectly for the entire weekend with just a minor tweak (the temporary removal of the potentiometer input)!

I have to admit I'm not convinced either, Hippy, it seems like a slightly illogical explanation. But I have to say it seems to "work" - during my simulations, the low seed value resulted in the result gradually increasing at randomnly but ever increasing increments. But it was definitely increasing for quite some time, not pushing out random numbers. When I seeded the variable with a large, 5 digit, number, the outputs were consistently (seemingly) random, with there not being any sort of obvious pattern to my mind.

At the end of the day, the "randomness" doesn't matter too much in my application - the program is only designed to simulate random shell flashes, and almost every user would perceive the final result as truly random, despite there never being any results below 10,000.

I'd certainly be more than happy to keep testing this seemingly odd phenomenon with the low seeds, but would definitely be interested in discovering what the final "cause" turns out to be!
 

lbenson

Senior Member
The low-value returns for a zero or low seed have been discussed before. If I can't start with a random number, I seed with some 5-digit prime. That still produces the same sequence unless you can introduce some true randomness.
 
Top