how to check a live time span for change

I hardly know how to describe what I'm needing, and maybe there's some examples already, but I haven't found any.
This code kinda shows what I need to do. I don't know how else to word it. The commented out part tells what I need, but I'm at a loss.

boolean CheckPosNeg(int Val) {
  timeRange = 1000; //within this time range
  changeCount = 3; //number of changes to trigger flag
  //if Val has changed from NEG to POS more than {changeCount} 
  //times in the past {timeRange} return TRUE
}

thanks!

"has changed" in the past time interval or "does change" in the future time interval?

How will the input value change?

Define an array that contains time stamp values. Every time the signal changes (NEG to POS) save the current time in the array, and check whether there have been the required number of changes in the given time span.

This sounds like what I am envisioning, but I'm afraid it's over my head. I worked on it an hour, and was more confused than when I started. I'll give it another go another day.

Also, the input value it a constrained reading of an IMU. -30 to +30 are it's limits

I worked on it an hour, and was more confused than when I started. I'll give it another go another day.

Break the problem into parts. Can you detect when the sign changes? Can you determine when that happened? Can you determine the difference between when the event happened and a reference time (now, for example)? Don't try to solve the whole problem at once.

This is what I’ve got so far. Is it a good way to start?

boolean CheckPosNeg(int Val) {
  
  if (Val == 0) return false; //when it's 0, it can be ignored
  int timeRange = 1000; //within this time range
  int changeCount = 3; //number of changes to trigger flag
  static int lastVal; //the last value passed
  static int countArray(changeCount); //I need to keep track of this many changes
  static unsigned long timeArray(changeCount);//this will hold a time stamp for each change
  if (Val > 0 && lastVal < 0) { //a change
      …UGH!
  }
}

Yeah that’s looking OK, what units are time being measured in? I take it that the 1000 in

int timeRange = 1000;

is milliseconds?

If the goal is to know when more than 3 changes have happened, then the array may need to be timeArray(changeCount+1);

I’m not sure countArray is needed. What is needed is an index to timeArray, which will point to the most recent value stored.

timeArray conceptually needs to work in a circle … a ring buffer. Another way to do it is to shift the whole array each time a new element is stored. This may be conceptually easier to envision, but is not as efficient, but for an array of four elements it probably doesn’t make much difference.

So the last line, the if statement, is good. Next step, if the condition is true, save Val to lastVal and save the current time to timeArray and increment the index for next time.

Sorry for the stream of consciousness, just trying to give some ideas to chew on :smiley:

Thanks. I think I got a loop set up. But I don’t think it’s working, but I must be close.

boolean CheckPosNeg(int Val) {

  if (Val == 0) return false; //when it's 0, it can be ignored
  int timeRange = 1000; //within this time range
  const int changeCount = 3; //number of changes to trigger flag
  static unsigned long lastVal; //the last value passed
  static int countArray(changeCount); //I need to keep track of this many changes
  static unsigned long timeArray[changeCount + 1];//this will hold a time stamp for each change {1,2,3}
  if (Val > 0 && lastVal < 0) { //a change
    for (int i=changeCount; i > 0; i--){
      timeArray[i] = timeArray[i-1]; //move all the value up the line
    }
    timeArray[0] = millis();
    lastVal = Val;
    //now see if it's been longer than [timeRange] for the least recent timestamp
    if (millis() - timeArray[changeCount] > timeRange) {
      return true; //send up red sparks!
    }
    else return false; //all is well
  }
}

I might have steered you wrong on

    lastVal = Val;

...try moving that outside the if. Need to always preserve the last value no matter what, correct? Then take action (the if) only if the proper condition is met.

I'm a little puzzled as to why a zero can always be ignored.

The other thing to think through (and I haven't) is the boundary conditions at start-up, i.e. until timeArray is full of legit values, will everything work properly?

I’ve gotten something to work!

boolean CheckPosNeg(int Val) {
//return false;
  const int ControlState = -2;
  if (Val == ControlState) return false; //when it's 0, it can be ignored
  int timeRange = 2000; //within this time range
  const int changeCount = 3; //number of changes to trigger flag
  static int lastVal; //the last value passed
  static int countArray(changeCount); //I need to keep track of this many changes
  static unsigned long timeArray[changeCount + 1];//this will hold a time stamp for each change {1,2,3}
        //Serial.println(Val);

  if (Val > ControlState) {
    if(lastVal < ControlState) { //a change
      for (int i=changeCount; i > 0; i--){
        timeArray[i] = timeArray[i-1]; //move all the value up the line
      }
      timeArray[0] = millis(); //put the current one at the beginning
      lastVal = Val; //update the lastVal
      //now see if it's been longer than [timeRange] for the least recent timestamp
      //Serial.println(timeArray[changeCount]);
      if (millis() - timeArray[changeCount] < timeRange) {
        Serial.println("Oscilate!");
        return true; //send up red sparks!
      }
      else return false; //all is well
    }
  }
  lastVal = Val;
 return false; 
}

You could use my statemachine library to keep track of polarities. It gives a little cleaner code.
The libray can be found here: http://playground.arduino.cc//Code/SMlib

This seems to be working:

#include <SM.h>

SM PolCheck(Undet);//Polarity is unknown on first call

int _val;//must be to global to be reachable from states

unsigned long TimeStamp[4];
unsigned TimeIdx;

void setup(){}//setup()

void loop(){}//loop()

boolean CheckPosNeg(int Val){
  _val = Val;//must be global to be reachable from SM
  EXEC(PolCheck);//call apropiate state function
  return millis()-TimeStamp[TimeIdx]<1000;
}//CheckPosNeg()

State Undet(){//first time call, polarity is unknown
  //determine polarity
   if(_val <0) PolCheck.Set(Neg); else PolCheck.Set(Pos);
  TimeSet();//make timestamp
}//Undet[]

void TimeSet(){
  TimeStamp[TimeIdx++] = millis();
  TimeIdx %= 4;
}//TimeSet()

State Pos(){
  if(_val < 0){//_val is negative, make timestamp and change state
    PolCheck.Set(Neg);
    TimeSet();
  }//if _val is negative
}//pos()

State Neg(){
  if(_val >= 0){//_val is positive, make timestamp and change state
    PolCheck.Set(Pos);
    TimeSet();
  }//if _val is positive
}//Neg()