Any good algorithms for normallizing jitter?

I am reading a pressure altitude sensor and trying to create a vertical speed value. Pretty straight forward; read 2 altitude values over a known interval and calculate a vertical speed.
The problem I am having is my altitude as read from the sensor is jumping around a bit even when sitting static. I get readings up to a foot or more different on successive reads. When sampling every 250 mS or so that can equate to VS values up to 240 ft/min or more.
I have tried reading 50 times and calculating an average but that isn’t working.
I was wondering if anyone knows of a method for reducing or calculating out this jitter? The sensor is a BME280 BTW.
Thanks

void loop() {
    float nowElev = 0;
    float t = bme.readTemperature();
    for (int i = 0; i < 50; i++) {
        float e = bme.readAltitude(SEALEVELPRESSURE_HPA) * 3.2808399;
        nowElev = nowElev + e;
    }
    nowElev = nowElev / 50;
    
    gNowTime = millis();
    if (gNowTime - gPreviousTime >= gUpdateInterval) {
        int elevChange = (nowElev - gPreviousElev) + .5;

        Serial.println();
        Serial.print(nowElev); Serial.print(" "); Serial.println(gPreviousElev);

        int vertSpeed = elevChange * 60000 / gUpdateInterval;
        gPreviousTime = gNowTime;
        gPreviousElev = nowElev;

        Serial.print("El = "); Serial.print(nowElev); Serial.print(" Ft AMSL  ");
        Serial.print("VS = "); Serial.print(vertSpeed); Serial.println(" Ft/Min");
}

That should work fine. What do you mean by “isn’t working”?

Here is an example reading an analog pin. I’m thinking it would be a simple solution to yours with a few tweaks.

# include <runningAvg.h>

runningAvg  smoother(5);   // Our smoother. You can change the number of datapoints it will act on.


// Standard setup stuff..
void setup(void) {

   Serial.begin(9600);
}


// Standard loop stuff..
void loop(void) {

   int aValue;
   float ave;

   aValue = analogRead(A0);               // Grab a value from the analog pin.
   ave = smoother.addData(aValue);        // Pop this value into our smoother. (Running average object.) Out pops the average.
   Serial.println();                      // From here down its just grabing info from the
   Serial.print(F("Entered    : "));      // Smoother and displaying it on the serial monitor.
   Serial.println(aValue);
   Serial.print(F("Average   : "));
   Serial.println(ave,4);
   delay(1000);                           // Yes delay() sucks but this is just to slow down an example.
}

You will need to grab LC_baseTools fro the library manager to compile this.

Good luck!

-jim lee

After reading 50 times and averaging it still jumps around enough to cause vertSpeed to bounce around.

Thanks. I’ll give that a try.

I wonder if you are averaging at the wrong frequency? Have you tried plotting the raw data?

-jim lee

Well, Doc Brown just basically did what I wanted to say, just simpler using a library. Anyway, if you didn’t want to use any external code like that ( I usually don’t since it really likes to break my stuff ), the implementation would be as follows:

  • Read altitude every 25 milliseconds or so ( you will need to find a healthy balance. If you have too much delay, the value you read will have a lot of influence or the filter will be slow )
  • Add that to an array, throwing out the oldest value ( by shifting the entire array)
  • Take the average of that array, weighing the oldest value least ( again, that’s based on trial and error if you don’t know how to calculate it )

This will basically ‘filter’ the high frequency jitter

EDIT: This is probably way harder than just using the library, but take some suggestions from it:

Read multiple values (you will have to figure out how many - more or longer delay will make the filter slower, fewer or shorter delay will decrease the effectiveness ), feed those into the rolling average ( I doubt 5 will be enough, but you’ll figure that one out ) and take the result every x-th cycle. Reading the result every cycle will just result in less amplitude on the jitter

1 Like

I really like that idea of weighting the later values more. I now wonder if I should add that into my stuff…

-jim lee

Isn’t that standard practice?

I donno’. Its been too many years since school. But it makes a LOT of sense.

-jim lee

Or you can run it through a low-pass filter:

  #define SMOOTHING_FACTOR 0.8  //between 0 (no smoothing) and 0.99 (maximum smoothing)
  
  static float smoothedValue = 0;
  float unsmoothedValue = 0;

  unsmoothedValue = GetTheCurrentDataValue();

  smoothedValue = (SMOOTHING_FACTOR * smoothedValue) + ((1 - SMOOTHING_FACTOR) * unsmoothedValue);  //low pass filter

I think this is easier than messing about with arrays and calculating averages. It is mathematically rigorous and widely used.

2 Likes

a7

This appears to take care of both weighing and past value storage in a very elegant way. It’s always based on a logarithmic curve, but I like the approach. Gonna be using this

1 Like

I made a typo with my variable names - corrected. :grinning:

I have had good success with the following:

  1. Read 20 values into an array
  2. Sort the values from high to lowest
  3. Discard the 3 highest and 3 lowest (will be the 3+3 outer elements of the array)
  4. Average the remaining values (will be the 14 inner elements of the array)

You can adjust the value of 20 and 3 according to the amount of jitter (noise) that you are getting. This is rather easy to implement and it surprisingly effective.

Good Luck!
dan

1 Like

So I have discovered a bit about this sensor. Regardless of how often the code fetches the data, the sensor only updates the data about every 100 mS. I was working under the assumption that it was working in real time.
What I have done is used Steve Thackery’s smoothing algorithm on the output vertical speed value which seems to give me the best results.
I will have to go for a drive and see what real changing data does but in the interim, thanks for everyone’s input.

That explains why your attempt to average 50 measurements “didn’t work”. You were probably averaging only 1 measurement, 50 times.

1 Like

and how is look modified code ?

#define SMOOTHING_FACTOR 0.95           //between 0 (no smoothing) and 0.99 (maximum smoothing)

float unsmoothedValue = 0;
static float smoothedValue = 0;

void setup() {
}

void loop() {

    gNowTime = millis();
    float t = bme.readTemperature();
    float nowElev = bme.readAltitude(SEALEVELPRESSURE_HPA) * 3.2808399;

    if (gNowTime - gPreviousTime > gUpdateInterval) {
        gPreviousTime = gNowTime;

        float elevChange = nowElev - gPreviousElev;

        float vertSpeed = elevChange * 60000 / gUpdateInterval;
        unsmoothedValue = vertSpeed;
        smoothedValue = (SMOOTHING_FACTOR * smoothedValue) + ((1 - SMOOTHING_FACTOR) * unsmoothedValue);  //low pass filter
        int vSpeed = smoothedValue + .5;

        Serial.print("gPreviousElev = "); Serial.print(gPreviousElev); Serial.print(" Ft AMSL  ");
        Serial.print("  nowElev = "); Serial.print(nowElev); Serial.print(" Ft AMSL  ");
        Serial.print("  elevChange = "); Serial.print(elevChange); Serial.print(" Ft");
        Serial.print("  VS = "); Serial.print(vertSpeed); Serial.print(" Ft/Min");
        Serial.print("  Smoothed = "); Serial.print(smoothedValue);
        Serial.print("  vSpeed = "); Serial.println(vSpeed);
        Serial.println();

        gPreviousElev = nowElev;
    }

}

Thanks