News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Positron8 - Pseudo Random Noise Generation experiments

Started by top204, Oct 23, 2024, 11:19 AM

Previous topic - Next topic

top204

I have an idea to make a realistic flame or glowing embers simulation using some WS2812B devices, and found I needed a method of producing 'Noise', as opposed to 'Random' values. So I looked up and studied some methods and created some procedures that look right, and give, what looks like, pseudo random values. But apparently, they are smoother so they are classed as 'noise'?

It is a mechanism that I am not fully familiar with, so I have listed a demo and the noise library code listing below for you to examine and test, if possible. Some of you may be more familiar with the 'noise' mechanism and give some guidelines.

The code listing below is the library code for noise procedures that will generate unsigned 8-bit integer, unsigned 16-bit integer, and Floating Point pseudo random noise values between min and max parameters:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Pseudo Random Noise generating procedures with min and max thresholds
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
' The flash memory table below holds random unsigned 16-bit values
'
    Dim Noise_RandTable As Flash16 = {31361, 62722, 59909, 54282, 43028, 20521, 41043, 16551,
                                      33103, 00670, 01341, 02683, 05367, 10735, 21471, 42943,
                                      20350, 40700, 15865, 31730, 63460, 61385, 57235, 48935,
                                      32334, 64669, 63802, 62068, 58601, 51667, 37798, 10060,
                                      20121, 40242, 14948, 29897, 59795, 54054, 42573, 19610,
                                      39220, 12904, 25808, 51617, 37698, 09860, 19720, 39440,
                                      13344, 26689, 53379, 41223, 16911, 33822, 02108, 04217,
                                      08434, 16868, 33737, 01938, 03876, 07752, 15504, 31009,
                                      62018, 58501, 51466, 37397, 09258, 18517, 37035, 08535,
                                      17070, 34140, 02744, 05489, 10979, 21958, 43916, 22296,
                                      44593, 23651, 47302, 29068, 58137, 50739, 35942, 06349,
                                      12698, 25396, 50793, 36051, 06567, 13135, 26270, 52540,
                                      39545, 13555, 27111, 54223, 42910, 20284, 40568, 15601,
                                      31203, 62406, 59277, 53019, 40503, 15470, 30940, 61881,
                                      58226, 50916, 36296, 07056, 14113, 28227, 56455, 47375,
                                      29215, 58431, 51327, 37119, 08703, 17407, 34814, 04092,
                                      08185, 16370, 32741, 65482, 65428, 65321, 65106, 64677,
                                      63819, 62102, 58669, 51803, 38071, 10606, 21213, 42427,
                                      19318, 38637, 11739, 23479, 46958, 28381, 56762, 47988,
                                      30440, 60881, 56226, 46917, 28298, 56596, 47657, 29779,
                                      59558, 53580, 41624, 17712, 35425, 05315, 10631, 21262,
                                      42525, 19514, 39028, 12520, 25040, 50081, 34626, 03717,
                                      07434, 14868, 29737, 59475, 53414, 41293, 17050, 34100,
                                      02665, 05331, 10663, 21326, 42653, 19770, 39540, 13544,
                                      27088, 54177, 42819, 20103, 40207, 14879, 29758, 59517,
                                      53499, 41462, 17389, 34778, 04020, 08040, 16080, 32161,
                                      64322, 63109, 60683, 55831, 46127, 26719, 53438, 41340,
                                      17144, 34288, 03041, 06082, 12165, 24330, 48661, 31786,
                                      63573, 61611, 57686, 49836, 34137, 02738, 05476, 10953,
                                      21907, 43814, 22093, 44187, 22838, 45676, 25817, 51634,
                                      37732, 09928, 19857, 39715, 13894, 27789, 55578, 45620,
                                      25704, 51408, 37280, 09024, 18048, 36097, 06659, 13319}

'-------------------------------------------------------------------------------------
' Generate a smooth unsigned 8-bit noise value
' Input     : pMin holds the minimum unsigned 8-bit value for the noise returned
'           : pMax holds the maximum unsigned 8-bit value for the noise returned
' Output    : Returns the unsigned 8-bit noise value
' Notes     : None
'
Proc Noise8(pMin As Byte, pMax As Byte), Byte
Static Global Dim wNoise_Index As Word Shared = 0
    Dim bValueA   As Byte
    Dim bValueB   As Byte
    Dim bFraction As Byte

    Do                                                                          ' Create a loop  
        bValueA = CRead16 Noise_RandTable[wNoise_Index]                         ' \ Read two consecutive noise values from the noise table
        wNoise_Index = (wNoise_Index + 1) // SizeOf(Noise_RandTable)            ' | Increment the noise index for the next call
        bValueB = CRead16 Noise_RandTable[wNoise_Index]                         ' /
        bFraction = wNoise_Index // SizeOf(Noise_RandTable)                     ' bFraction determines the interpolation amount between the two values
        Result = bValueA + ((bValueB - bValueA) * bFraction / SizeOf(Noise_RandTable))  ' Calculate the smooth noise using interpolation      
        Select Result                                                           ' \
            Case pMin To pMax                                                   ' | Exit the loop if the noise value is between the pMin and pMax parameters
                Break                                                           ' |
        EndSelect                                                               ' /
    Loop                                                                        ' Continue generating noise until it is within the valid range
EndProc

'-------------------------------------------------------------------------------------
' Generate a smooth unsigned 16-bit noise value
' Input     : pMin holds the minimum unsigned 16-bit value for the noise returned
'           : pMax holds the maximum unsigned 16-bit value for the noise returned
' Output    : Returns the unsigned 16-bit noise value
' Notes     : The procedure reads two noise values from the Noise_RandTable,
'             calculates a fraction to interpolate between them, and adds a small random offset for variation.
'             The result is scaled to fit the range between pMin and pMax, ensuring smooth transitions without repetitive values.
'             If the generated value exceeds the bounds, it recalculates a new noise value that stays within the thresholds.
'
Proc Noise16(pMin As Word, pMax As Word), Word
Static Global Dim wNoise_Index As Word Shared = 0
    Dim wRandA      As Word
    Dim wRandB      As Word
    Dim wInterNoise As Word
    Dim wRandOffset As Word
    Dim fFraction   As Float

    Do                                                                          ' Create a loop
        wRandA = CRead16 Noise_RandTable[wNoise_Index]                          ' Read a random value from the flash table
        wNoise_Index = (wNoise_Index + 1) // SizeOf(Noise_RandTable)            ' Move to the next value in the table, with wrap around
        wRandB = CRead16 Noise_RandTable[wNoise_Index]                          ' Read the random value from the flash table
        fFraction = (Random // 100) / 100.0                                     ' Fraction for interpolation (based on random phase shifting for smoother noise)
        wInterNoise = (wRandA + ((wRandB - wRandA) * fFraction))                ' Noise_Interpolate between two random values
        wRandOffset = Random // ((pMax - pMin) / 50)                            ' Add a small random offset to avoid repetitive values
        Result = pMin + ((wInterNoise // (pMax - pMin)) + wRandOffset)          ' Scale the interpolated noise value to the min and max range and add the offset
        Select Result                                                           ' \
            Case pMin To pMax                                                   ' | Exit the procedure if the noise value is between the pMin and pMax parameters
                ExitProc                                                        ' |
        EndSelect                                                               ' /
    Loop                                                                        ' Continue generating noise until it is within the valid range
EndProc

'-------------------------------------------------------------------------------------
' Linear interpolation for smoothing noise transitions
'
Proc Noise_Interpolate(pVal1 As Float, pVal2 As Float, pFract As Float), Float
    Result = (pVal1 * (1.0 - pFract))
    Result = Result + (pVal2 * pFract)
EndProc

'-------------------------------------------------------------------------------------
' Generate a smooth floating point noise value with min and max thresholds
' Input     : pMin holds the minimum noise value allowed to be generated
'           : pMax holds the maximum noise value allowed to be generated
' Output    : Returns a floating point noise value
' Notes     : Noise is based on a sine wave for smoother transitions
'
Proc NoiseF(pMin As Float, pMax As Float), Float
Static Global Dim Noise_fPhaseShift As Float = 0.0
Static Global Dim Noise_fPhaseSpeed As Float = 0.01
Static Global Dim wNoise_Index As Word Shared = 0                               ' Index for tracking current noise position
    Dim wNoiseA     As Word
    Dim wNoiseB     As Word
    Dim fInterNoise As Float
    Dim fFraction   As Float
    Dim fTemp       As fInterNoise
 
    Do                                                                          ' Create a loop
        wNoiseA = CRead16 Noise_RandTable[wNoise_Index]                         ' \     
        wNoise_Index = (wNoise_Index + 1) // SizeOf(Noise_RandTable)            ' | Read two consecutive noise values from flash memory
        wNoiseB = CRead16 Noise_RandTable[wNoise_Index]                         ' /
        '
        ' Calculate fFraction based on a sine wave for smoother transitions
        '
        Noise_fPhaseShift = Noise_fPhaseShift + Noise_fPhaseSpeed
        If Noise_fPhaseShift >= 1.0 Then
            Noise_fPhaseShift = 0.0
        EndIf
        fTemp = Noise_fPhaseShift * 3.1415                                      ' \
        fTemp = fTemp * 2.0                                                     ' | Sine wave modulation for smooth transition
        fFraction = Sin(fTemp) + 1.0                                            ' |
        fFraction = fFraction / 2.0                                             ' /

        fInterNoise = Noise_Interpolate(wNoiseA, wNoiseB, fFraction)            ' Interpolate between two noise values 
        Result = pMin + ((pMax - pMin) * (fInterNoise / 65535.0))               ' Scale the value into the desired range
        Select Result                                                           ' \
            Case pMin To pMax                                                   ' | Exit the loop if the noise value is between the pMin and pMax parameters
                Break                                                           ' |
        EndSelect                                                               ' /
    Loop                                                                        ' Continue generating noise until it is within the valid range
EndProc

Copy the listing above, and make a file named "Noise.inc" from it.

It seems to work well, but it just looks like random values to me. :-) I may modify them to actually use a 'real' Random value generator using an ADC channel for the random bits that are then combined to make random values.

Below is a code listing for a demo of the "Noise.inc" library, that generates the noise and transmits the results to a serial terminal:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Pseudo Random Noise procedures demonstration.
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F26K22                                   ' Tell the compiler what device to compile for
    Declare Xtal = 16                                   ' Tell the compier what frequency the device is operating at (in MHz)
    Declare Float_Display_Type = Fast                   ' Use the faster and more accurate floating point to ASCII conversion
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6

    Include "Noise.inc"                                 ' Load the noise procedures into the program
'
' Create global variable here
'   
    Dim bNoise_Value As Byte
    Dim wNoise_Value As Word
    Dim fNoise_Value As Float

'-------------------------------------------------------------------------------------
' The main program starts here
' Generate 8-bit, 16-bit and floating point Random Noise values
' and transmit the results to a serial terminal
'
Main:
    Do                                                  ' Create a loop
        bNoise_Value = Noise8(100, 200)                 ' Generate an 8-bit noise value between 100 and 200
        HRSOut1Ln "Byte : ", Dec bNoise_Value
       
        wNoise_Value = Noise16(100, 1000)               ' Generate a 16-bit noise value between 100 and 1000
        HRSOut1Ln "Word : ", Dec wNoise_Value
       
        fNoise_Value = NoiseF(0.0, 1.0)                 ' Generate a floating point noise value between 0.0 and 1.0
        HRSOut1Ln "Float: ", Dec2 fNoise_Value    
        DelayMS 100
    Loop                                                ' Do it forever

The next thing is to get the framework of the flame and embers code up and running using my WS2812B RGB LED library.

Now.... Where do I start??? LOL.

JonW

Les I tried to run it on the 27j53 but it doesnt put out the correct data.  comms is working as it outputs the text and it obviously compiles. Running at 16M direct from the crystal.


top204

The program is not using any specialised peripherals or SFRs, so it will run on any device, and running the loop with the separate noise procedures, it transmits:

For the Floating point:

Float: 0.73
Float: 0.93
Float: 0.86
Float: 0.72
Float: 0.43
Float: 0.52
Float: 0.35
Float: 0.43
Float: 0.12
Float: 0.01
Float: 0.03
Float: 0.07
Float: 0.15
Float: 0.30
Float: 0.62
Float: 0.33
Float: 0.60
Float: 0.26
Float: 0.47
Float: 0.95
Float: 0.93
Float: 0.87
Float: 0.74
Float: 0.49
Float: 0.98
Float: 0.97
Float: 0.94
Float: 0.89

And for the 16-bits:

Word : 772
Word : 180
Word : 864
Word : 779
Word : 376
Word : 828
Word : 599
Word : 134
Word : 831
Word : 365
Word : 353
Word : 416
Word : 791
Word : 862
Word : 235
Word : 236
Word : 383
Word : 746
Word : 774
Word : 656
Word : 929
Word : 577
Word : 489
Word : 275
Word : 948
Word : 442
Word : 697
Word : 432
Word : 492
Word : 933
Word : 501
Word : 615

And for the 8-bit:

Byte : 128
Byte : 164
Byte : 154
Byte : 128
Byte : 186
Byte : 134
Byte : 196
Byte : 137
Byte : 146
Byte : 128
Byte : 155
Byte : 139
Byte : 113
Byte : 193
Byte : 131
Byte : 138
Byte : 121
Byte : 200
Byte : 144
Byte : 109
Byte : 106
Byte : 147
Byte : 188
Byte : 120
Byte : 116
Byte : 101
Byte : 108

I got the above values using a PIC18F27J53, but had to change the transmit to RSout because it appears the 18F27J53 uses a different type of PPS and the USART commands are not working with it. I'll see if I can work out what microchip have done for the PPS on this device, because it is different for a few types of device, and with this type being old, I did not realise it used an early version of PPS!

trastikata

Hello Les,

out of curiosity, can you try generating say 10000 8-bit samples and run it through a FFT tool to see if a frequency will pop-up? Or if can you generate the text file with values and post it, I can run it through a FFT tool.


JonW

Cheers, Ill take a look, odd how I got text out.  Its an old part but its a great device for comms.  I can dig out a 27k22 dev board and try it on that.

Many moons ago, I did a LFSR noise generator with a moving average to cause more randomness from a PRNG, I did look at perlin noise at the time but it was deemed too much for the old space qualified 8bit parts we were using and the original work was done in python. I will see if I can find it and port it to basic or run it and plot it against your output, I am sure it would produce something like a flame flicker.

2D perlin noise may be a good way to generate a flame for an LED matrix

top204

The procedures are based upon a perlin noise mechanism. Some studies of the perlin mechanism show that it also uses interpolation and is why the Sin is used in the floating point procedure.

However, I stopped reading and looking at mechanisms when it got to the stage were one study disagreed with the other and the complexity of making pseudo "random" values got way over the top and one type is never quite right to some "experts" so do it this way, then another group of "experts" state that, "it is not quite right" as well etc... Then using things like quadratic and cubic functions on the "random" values? :-)

Waaaaaaaaaay over the top for some pseudo random values that do not jump around too much. LOL.


JonW

Yeah I know what you mean, we worked with a company in China that stated they had a quantum noise generator IC for encryption and it was going to be used in the banking links such that it would follow the heisenburg uncertainty principle where anyone observing or attacking the fibre link would instantly cause the data to be destroyed, they were fanatical about the random nature of randomness.  The point where they hacked the cell phones of our visiting party worried me.  Luckily I was paranoid before we went there so left everything in the hotel!  I never did see the IC they were sayiny they had developed...

Ill have a look at the procs, all good fun




John Lawton

The thing about random is that it can deliver a sequence of values that an observer wouldn't consider 'random', e.g. 2,2,2,2,2,2 etc would be quite possible and useless for a lighting sequence for instance.

So actually what I call quasi-random is sometimes required which I once created by using code that checks that each consecutive 'random' digit is actually different to it's neighbour.

John

trastikata

I think for the purpose of 99.99% of the 8-bit PIC application it would be random enough, I was just curious how random is a algorithm based white noise. Anyway I found an old board with SD card port and will test it today for "academic research".  ;D 

top204

It's a bit like the theoretical "chaos" theory, where order exists in 'everything', even in things that have no observable order at all.

Wow... Powerful thoughts for a random number generator, and it will be random, as far as the chaos theory allows :-), when I add a random noise generator (a transistor) to the ADC input.

JonW

It's a bit like the theoretical "chaos" theory, where order exists in 'everything', even in things that have no observable order at all.

Reminds me of Nash Equilibrium. 

top204

However, apparently, in the quantum universe, there is no order at all, and sub atomic particles, and especially electrons and photons, move about in an absolute random fashion, but it is the random clustering of the sub-atomic particles that creates matter!

I find that very hard to believe, but it seems to be the current theory behind it.

But there have been many previous theories that have been forgotten and moved onto the next. i.e String theory, and the silly theory that there is actually only a single electron in the whole universe, but it can be everywhere at once, and over time it looks like seperate electrons?

trastikata

Quote from: top204 on Oct 25, 2024, 10:02 AMHowever, apparently, in the quantum universe, there is no order at all and sub atomic particles, and especially electrons and photons, move about in an absolute random fashion....

Les, I'd say there's order and rules and laws in everything, we simply don't know them, yet! :)

Like a true physicist would always say: "Within the frame of the current scientific knowledge ..."