Fuzzy Timing

I need a little help trying to make a timer a little fuzzy. I want to use a fixed interval of timing like this:

____|_______|____|_____|_________|_____|___|_______|

where the pipe is the event occurrence and the underscore is the delay in an array like this:

int myIntervals = { 1000, 2000, 750, 850, 1200, 850, 500, 1000};

but the values are arbitrary.

I would like to create a slight randomness to the event, but not allow the randomness to affect the overall timing:

___*|*_____*|*__*|*___*|*_______*|*___*|*_*|*_____*|

where the randomness is described as the time contained by asterisks.

So the event always happens at the interval +- a random delay:

int fuzzyPeriod = random(-75, 75);

I've experimented around this but to no avail... I'm finding myself in a recursion when the fuzzy period is negative:

{
  if(millis() - lastMillis >= nextInterval)
  {
    //do something
    if(index >= numIntervals) // reset the counter for the interval array
    {
      index = 0;
    }
    lastMillis += myInterval[index];  allways add a fixed, predefined segment of time
    index++;
    fuzzyPeriod = random(-75, 75);  // the constant is arbitrary but assume alway less than myInterval when multiplied by 2
    nextInterval = myInterval[index] + fuzzyPeriod;
  }
}

I hope I've done a good job explaining... I cannot for the life of me get this done and I know I'm to the point where I need a little help!

the randomness is described as the time contained by asterisks.

If you know the total period represented by the pairs of asterisks then you could make the first asterisk period random within a range and the second one the total period minus the first random period.

UKHeliBob:
If you know the total period represented by the pairs of asterisks then you could make the first asterisk period random within a range and the second one the total period minus the first random period.

I can keep on schedule by advancing through the array:

lastMillis += nextInterval

kind-of-thing...

how to keep the random offset from telegraphing down the line? Agree, maybe make the Interval array shorter by half the width of the asterisk range...

It seems doable, until I try!

You need to keep a record of the previous fuzzyPeriod and use that to adjust nextInterval to stop the fuzziness cascading.

In case it matters...

random(-75, 75)

...is not symmetric around zero; the upper bound (75) is excluded.

You could store the real interval and add randomness to what is used, then set the next interval start as the last start plus the real interval.

if ( millis() - start >= fuzzy )
{
// do something
start += interval;
fuzzy = interval + random();
}

sure thing, but it doesn't really matter that much, as you probably expected, and it is easy to make it so.

GoForSmoke:
You could store the real interval and add randomness to what is used, then set the next interval start as the last start plus the real interval.

if ( millis() - start >= fuzzy )
{
// do something
start += interval;
fuzzy = interval + random();
}

it seems like that, but darn if it doesn't seem to work when the random adjustment happens to be negative...

I have to sit in a quiet place with graph paper...

BulldogLowell:
it seems like that, but darn if it doesn't seem to work when the random adjustment happens to be negative...

Perhaps because you're using unsigned long for time?

If you maximum interval will be less than 25 days, you can get away with using long for time.

PS -- also watch out that you don't have a 50ms interval and a more than +/-50ms random when subtracting.

The simpler thing to do is keep the unsigned long and add 0 to max randoms.

Bulldog, take a break, your head is inside the box your design made. Think outside the box!

I spent a few minutes playing with your problem. This works by first calculating the relative event times based on your fixed intervals, making these event times fuzzy within a range, then going back to give you the interval.

unsigned long myIntervals[8] = { 1000, 2000, 750, 850, 1200, 850, 500, 1000};

// myRelEventTime:     relative time of each event relative to start time (mS from start time)
// myRelEventTimeFuzzy:      time of each event relative to start time randomised +/- X mS  (mS from start time)
// myNewIntervalFuzzy: (optional) if you want a new interval (mS) instead of just relative time of event 

unsigned long myRelEventTime = 0 ;
unsigned long myRelEventTimeFuzzyLast = 0 ;
void setup() {
  Serial.begin(9600);
  Serial.println() ;
  Serial.println ( "myInterval; myRelEventTime; myRelEventTimeFuzzy; myNewIntervalFuzzy  ") ;
  for ( int i = 0 ; i < 20 ; i ++ ) {
    int index =  i  % 8 ;

    Serial.print (myIntervals[index]) ;
    Serial.print ("; " ) ;
    
    myRelEventTime +=  myIntervals[index] ;
    Serial.print (myRelEventTime) ;
    Serial.print ("; " ) ;
    
    unsigned long myRelEventTimeFuzzy = myRelEventTime + random(-75, 75);
    Serial.print (myRelEventTimeFuzzy) ;
    Serial.print ("; " ) ;
    
    // optional if you want the fuzzy interval as well as the fuzzy relative time 
    unsigned long myNewIntervalFuzzy =  myRelEventTimeFuzzy -  myRelEventTimeFuzzyLast ;
    Serial.print (myNewIntervalFuzzy) ;
    Serial.print ("; " ) ;
    
    myRelEventTimeFuzzyLast = myRelEventTimeFuzzy ;
    Serial.println() ;
  }
}

void loop() {}

BulldogLowell:
I need a little help trying to make a timer a little fuzzy.

GoForSmoke:
Bulldog, take a break, your head is inside the box your design made. Think outside the box!

if (startMillis < millis()) // let’s wait until this is satisfied!!!

int sequence[] = {1000, 750, 950, 1150, 1200, 1500, 1000, 1900, 2000};
unsigned int index;
unsigned long startMillis = 0;
unsigned int fuzzy = sequence[0];

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
}

void loop()
{
  if (startMillis < millis())  // let's wait until this is satisfied!!!!!
  {
    if (millis() - startMillis >= fuzzy)
    {
      digitalWrite(13, !digitalRead(13));
      startMillis += sequence[index];   // advance startMillis by the last interval used
      index++;
      if (index >= sizeof(sequence) / sizeof(sequence[0]))
      {
        index = 0;
        Serial.println("Restarted Sequence");
      }
      fuzzy = sequence[index] + random(-75, 76);  // Coding Badly ;)
      Serial.print("fuzzy = ");
      Serial.println(fuzzy);
      //index++;
    }
  }
}

I think that does it, I just need to test it out on my scope :wink:

@aarg that actually helped!!
@6v6gt karma++
@GoForSmoke thanks!
@Coding Badly :wink: ++

if (startMillis < millis())

That will let you down or bite you when startMillis is past the rollover from millis().

Randoms do not have to go from - to +, they can be entirely >= 0.

If every interval has positive random added, the time from one to the next will vary the same as if the more code-intensive methods needed to add negatives and then cleanly deal with the results as exceptions … except positives only would use less code and run quicker.

How about make the randoms some power of 2 fraction of the array interval?
Like (interval >> 2) for 1/4th?

GoForSmoke:

if (startMillis < millis())

That will let you down or bite you when startMillis is past the rollover from millis().

Rats, you are correct, and my project won’t respond well to that type of failure, it will get all out of sync.

I’m going to solve this and have it survive the millis() overflow, by golly.

Stick to subtracting unsigned values then there is no overflow problem.

All you need to do is not add negative values for the fuzzy. Random( 0, 150 ) is as good as random( -75, 75 ). When at every interval it is add, the time from one to the next will simply be averaged around the interval plus half the random range. It just moves all the times up a bit, from 'peak' to 'peak' is the same as if you used -75 to 75.
Just make sure that the random never reaches the next interval ( 50ms interval with +0 to 150 is bad) whic is why I suggest that the random is 0 to (interval >> 2) or like, then impossible to violate the next interval.

GoForSmoke:
Just make sure that the random never reaches the next interval ( 50ms interval with +0 to 150 is bad) whic is why I suggest that the random is 0 to (interval >> 2) or like, then impossible to violate the next interval.

agree it needs a test for a collision of time fences...

keep the faith/

BulldogLowell:
agree it needs a test for a collision of time fences...

keep the faith/

I've tried to show you twice... you don't need the checks if you never let it get out of range.

But you have another wrinkle and what I tell ya.

Below, intervals are from your array. Where they happen is fixed but not where change is made.
The change is the interval plus the fuzzy always within the interval because always a fraction of the interval. No collision, no bounds checks needed.

interval 0
------------- plus fuzzy
interval 1
------------- plus fuzzy
interval 2
------------- plus fuzzy
interval 0
------------- plus fuzzy
interval 1
------------- plus fuzzy

However you still need to get from fuzzy to fuzzy cleanly.

I would suggest that when the fuzzy time is reached that start = millis() and the millisToNextFuzzy would be the interval minus the random used to get the fuzzy plus however much the next fuzzy randoms out to being [ random( 0, fractionOfNextArrayInterval) ].

Your changes will always be inside of the current array interval, you won't need checks.