Algorithm to filter spikes

Hi guys…

I am working with a Maxbotix XL Sonar sensor.
The output pulse of that sensor (pin 2) varies in width when it sees an object in it’s sights.
58 microsecs = 1 cm.
So 44.4 mS = 765 cm. (it’s max reading distance)
I am using PulseIn to read with pulse width.
This works fine but you do get spikes occasionally with no object around.
I am currently testing in my basement so I am probably getting side clutter spikes.
Is there any algorithms out there (I’m sure there are) to filter this so an occassional spike or two in a row is ignored?
I get a reading from the sensor every 100 mS.
Right now I just let a variable used as a counter run between 0 and 20.
It INC’s on an object and DEC’s on no object.
When the variable is > 9 it says there is an object.
Here is my code:

void loop() 
{
    
  duration = pulseIn(sensor_pin,HIGH,timeout);
  
  inches = (duration/58)*0.3937008; // convert centimeters to inches
      
  if (inches < distance) 
  {
    z++;
  }
      else
  {
    z--;
  }
  if (z > 20) z=20;
  
  if (z < 0) z=0;
  
  if (z > 9)
  {
    
    digitalWrite(12,HIGH); 
  }
      else 
  {  
    digitalWrite(12,LOW);  
  } 
  
}

Thanks for any help or code!
I have just recently gotten an Arduino Uno and like this forum a lot.
BTW, why did I convert to inches from centimeters?
I was testing accuracy of the sensor and printing the output to the serial monitor.
:wink:

There are several ways of dealing with spikes, depending on what you are trying to accomplish. You could call pulseIn in a loop, and read 5 values and add them up. After the loop, divide the sum by 5, to get an average distance.

You could make a copy of the current reading at the end of loop, and compare the new reading to the previous reading. If the difference is small, accept the new reading. Otherwise, ignore it.

A lot depends on how big the spikes are in comparison to the average reading, whether the spike should influence the average, or not, and how much variation there is in the average reading, in particular how fast the average reading changes.

BTW, why did I convert to inches from centimeters?

Whether you did depends on what the data sheet told you about the output of the sensor, what those magic numbers mean, and what types the variables involved have. Without seeing all of your code, we can’t tell.

As to why, only you can tell us that.

Use numbers based in power of 2, they are way faster to divide than other values.
Just read the sensor 2,4,8,16 times and then divide the result, its called a mean value and its very used as a simple filter.

Thanks for the input!
Here is the whole sketch:

/*
 Ultrasonic_Read_Serial v.13 11/27/10
 Reads a digital input on pin 4, prints the result to the serial monitor 
 
 
*/

unsigned long duration;
int inches;
int distance = 84; // this is threshold distance to show car presence in inches (84 = 7 feet)
int sensor_pin = 4; 
int x=0;
int y;
int z=0;
int feet;
int remainder_of_inches;


void flash_13_500()    // This function returns nothing - It simply flashes pin 13 on and off 5 times
{ 
  for(y=0;y<5;y++)
  {
 
  digitalWrite(12,HIGH);
  delay(500);
  digitalWrite(12,LOW);
  delay(500);}
}
void flash_13_250()    // This function returns nothing - It simply flashes pin 12 on and off 5 times
{ 
  for(y=0;y<3;y++)
  {digitalWrite(12,HIGH);
  delay(250);
  digitalWrite(12,LOW);
  delay(250);}
}

void flash_13_125()    // This function returns nothing - It simply flashes pin 12 on and off 5 times
{ 
  for(y=0;y<5;y++)
  {digitalWrite(12,HIGH);
  delay(125);
  digitalWrite(12,LOW);
  delay(125);}
}

void feet_inches()                      // Prints inches as feet and inches
{
  remainder_of_inches = inches % 12;
  feet = (inches-remainder_of_inches)/12;
  Serial.print(feet,DEC);
  Serial.print(" Feet, ");
  Serial.print(remainder_of_inches,DEC);
  Serial.print(" Inches");
  Serial.println("");
}
  void setup()
{
  Serial.begin(9600);                // Set the baud rate for the serial port
  pinMode(12, OUTPUT);               // Set pin 12 as an output
  pinMode(sensor_pin, INPUT);        // This is the input  from the ultrasonic sensor (this connects to pin 2 on the sensor)
  digitalWrite(12, LOW);             // initialize the LED off which means no car present
}

void loop() 
{
    
  duration = pulseIn(sensor_pin,HIGH);
  
  inches = (duration/58)*0.3937008; // convert centimeters to inches
      
  if (inches < distance) 
  {
    z++;
  }
      else
  {
    z--;
  }
  if (z > 20) z=20;
  
  if (z < 0) z=0;
  
  if (z > 9)
  {
    
    digitalWrite(12,HIGH); 
  }
      else 
  {  
    digitalWrite(12,LOW);  
  } 
  
}

void debug_print() 
{
  Serial.print("Number =");
  Serial.print(x);
  Serial.print("\t");
  Serial.print("Duration =");
  Serial.print(duration , DEC);
  Serial.print("\t");
  Serial.print("Inches =");
  Serial.print(inches , DEC);
  Serial.print("\t");
  Serial.println("");   // carriage return
}
  
void print_failure()
{
if (inches == 0) 
  {
  Serial.print("***SENSOR FAIL TIMEOUT***");
  Serial.println("");
  } 
}

The object ( a railroad car ) will be traveling at up to 30 fps.
The filter must operate “on the fly” to detect the object within a second.

Thanks!

  feet = (inches-remainder_of_inches)/12;

Compilers ignore white space, so you could make this statement much more readable by humans, by adding spaces before and after the -.

On the other hand, there is no reason to subtract remainder_of_inches (or to use that long a name, either).

Suppose inches was 242. remainder_of_inches would be 2. 242/12 and 240/12 are the same value, when integer arithmetic is performed.

Consistent indenting, consistent use of white space, and lining up { and } (each on their own line) will also make your program much easier to follow.

So will using names that actually reflect what they are doing:

void flash_[glow]13[/glow]_500()    // This function returns nothing - It simply flashes pin [glow]13[/glow] on and off 5 times
{
  for(y=0;y<5;y++)
  {

  digitalWrite([glow]12[/glow],HIGH);
  delay(500);
  digitalWrite([glow]12[/glow],LOW);
  delay(500);}
}

PaulS,

Thanks for your constructive criticism.

Compilers ignore white space, so you could make this statement much more readable by humans, by adding spaces before and after the -.

On the other hand, there is no reason to subtract remainder_of_inches (or to use that long a name, either).

I understand about white space and naming variables and functions that make sense. I thought “remainder_of_inches” pretty well spelled out what it meant. There is nothing wrong with a long name if it makes more sense to you. I am lost when you say I didn’t need that variable though. I create and use it in a function that simply prints “feet” and “inches” to the serial monitor of how far away my test object may be from the sensor. I am not a mathematician and guess I don’t understand integer arithmetic.

Suppose inches was 242. remainder_of_inches would be 2. 242/12 and 240/12 are the same value, when integer arithmetic is performed.

242 / 12 = 20.166 which would round down to 20
240 / 12 = which is exactly 20
242 % 12 = 2
240 % 12 = 0

Using % 12 gives me the remainder of inches that do not fit perfectly into groups of twelve. Right?
Then when I subtract that from the total inches and divide by 12 I get feet.
This was done so the screen print would display “feet” and “inches” properly.
You’ll notice it isn’t even being called in the program.
If you have an easier way to do it with less coding I would love to see it as I am always learning.

And lastly, the discrepancy between 12 and 13 was because 13 had the LED for debugging and 12 was to be the final pin for driving an output. I just hadn’t cleaned it up yet.

Here is the final code so far:

/*
 Ultrasonic_Read_Serial v.14 11/28/10
 Reads a digital input on pin 4 and activates pin 12 when requested
 
 
*/

unsigned long duration;                 // Holds the pulse length from the sensor 
int inches;
int distance = 84;                      // this is threshold distance to show car presence in inches (84 = 7 feet)
int sensor_pin = 4;                     // Connects to pin 2 of the ultrasonic sensor
int x = 0;
int y;
int z = 0;
int feet;
int remainder_of_inches;                // This is just used in my debugging of the program using serial monitor so I can see what is going on

void feet_inches()                      // Prints inches as feet and inches 
                                        // Only used for debugging
  {
    remainder_of_inches = inches % 12;
    feet = (inches - remainder_of_inches)/12;
    Serial.print(feet,DEC);
    Serial.print(" Feet, ");
    Serial.print(remainder_of_inches,DEC);
    Serial.print(" Inches");
    Serial.println("");
  }
  
void setup()

  {
    Serial.begin(9600);                   // Set the baud rate for the serial port
    pinMode(12, OUTPUT);                  // Set pin 12 as an output
    pinMode(sensor_pin, INPUT);           // This is the input  from the ultrasonic sensor (this connects to pin 2 on the sensor)
    digitalWrite(12, LOW);                // initialize the LED off which means no car present
  }

void loop() 

  {    
    duration = pulseIn(sensor_pin,HIGH);  // duration is the pulse width in microseconds
    inches = (duration / 58) * 0.3937008; // This converts centimeters to inches because I have problems visualizing centimeters. ( 58 microseconds = 1 cm) 
      if (inches < distance)              // This compares the distance seen by the sensor to my trigger distance 
        { z++; }
          else
        { z--; }
    if (z > 20) z = 20;
    if (z < 0) z = 0;
    if (z > 9)  
      { digitalWrite(12,HIGH); }
        else 
      { digitalWrite(12,LOW);  } 
  }

Now back to my original reason for the first post in this thread…

Filtering…does anyone have any examples or can you point me in the right direction?

How many clock cycles does the multiply by 0.3937008 take?

Thanks for all your help!

I thought “remainder_of_inches” pretty well spelled out what it meant.

It does. The only problem is that it is so long that I made three mistakes typing it, and had to fix them. Personally, I like names to be as short as possible, without being too short. But, that’s a personal issue that might not matter to you. If it doesn’t please ignore my comment. I won’t be offended.

I am lost when you say I didn’t need that variable though.

I never said you didn’t need it. I said that you didn’t need to subtract it from inches just to make sure that the compiler had nothing to truncate. You point out that 242/12 is 20.166 inches, but that isn’t true. 242.0/12.0 is 20.166, but 242/12 is 20.

Using % 12 gives me the remainder of inches that do not fit perfectly into groups of twelve. Right?

Yes, and it’s a quite handy feature.

PaulS,

So because "feet" and "inches" are declared as "int" then...

feet = inches / 12;

That will drop the remainder and just give the number of feet.

That will drop the remainder and just give the number of feet.

Exactly. And it's exactly how humans do it.

Cool!

I wasn't considering the way the variables did arithmetic, just that they were big enough to not overflow.
Any thoughts on filtering?

It goes back to the questions I asked in Reply #1. Are you trying to average readings, or exclude out-liers? Either one can be done.

I want to rule out the occasional spike but still return a positive response within a second.
I get 10 reads in a second.

So, you keep a running average, say the last 10 readings. Anything significantly above or below that average gets ignored.

Search the forum for FIFO.h (first in, first out - a queue). Add each new reading (that is valid) to the end, and remove the oldest reading (if there are more than 10). Then, compute the average.

It will take a few seconds to determine an average, but after that, outliers can be detected and ignored.

Thanks PaulS!

I have located SimpleFIFO.h

Is that suitable?

Is there a tutorial on using libraries?

Is that suitable?

Yes.

Is there a tutorial on using libraries?

It's such a simple thing, I'm not sure why you need a tutorial.

#include SimpleFIFO.h
and call the functions defined in the header file.