how to smoothing filter

Write your question here.
I have a program that gives a distance reading ok. However it jumps around a lot so I need to make a smoothing filter. The print line prints an
int distance
and the value is in inches. I would like to make a filter to take the last 10 readings and divide by 10 and print that number instead of the first one distance. distance average for example.



1
2
3
4
5
6
7
8
pc.print "distance";
Assume I should start by adding an array
array [9]
?? how to automatically add new reading to array and loose oldest reading.
add all 10 numbers and divide by 10 = value
distance average = value
pc.print "distance average";



My searches have revealed many volumes of information on very complicated questions but nothing I can use on a simple problem. If there is a simple answer to my question by all means please point me to it. Thanks.
?? how to automatically add new reading to array and loose oldest reading.
Where is the data coming from? A file, keyboard, sonar device ...
yes it is an hc-sr04 sonar device. It works witht he code that i got from the net just fine. it is just not so stable in the readings
Ok. So can you give say a sample of 100 readings?
Often by looking at the nature of the noise you can better work out how to remove it as averaging may not be the best solution.
Maintain the measurements in a queue. When you've gotten up to 10 measurements you can start removing the oldest measurement from consideration and add the new measurement. This example lets you drive it with keyboard input. Surely you could adapt the concepts in the MeasurementProcessor class to whatever data stream you're actually using.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <queue>

class MeasurementProcessor
{
private:
    unsigned int smoothingWindowSize;
    std::queue<double> measurements;

    //the measurementSum variable is used to hold the sum of all the
    //measurements we're currently holding in the queue. We will adjust
    //it as we put things in and take things out of the queue.
    double measurementSum;

public:
    MeasurementProcessor(unsigned int windowSize) :
        smoothingWindowSize(windowSize == 0 ? 1 : windowSize), //do this to prevent a window size of 0
        measurementSum(0.0),
        measurements()
    { }

    void addMeasurement(double newMeasurement)
    {
        measurements.push(newMeasurement);
        measurementSum += newMeasurement;

        if(measurements.size() > smoothingWindowSize)
        {
            measurementSum -= measurements.front();
            measurements.pop();
        }
    }

    double getSmoothedReading()
    {
        //should check that measurements.size() isn't 0, and handle according to your needs
        return measurementSum / measurements.size();
    }
};

int main()
{
    const int SMOOTHING_WINDOW_SIZE = 10;
    MeasurementProcessor mp(SMOOTHING_WINDOW_SIZE);

    double measurement = 0.0;
    while(true)
    {
        std::cout << "Enter measurement: ";
        std::cin >> measurement;

        mp.addMeasurement(measurement);
        std::cout << "Smoothed out over last " << SMOOTHING_WINDOW_SIZE << " measurements: "
                  << mp.getSmoothedReading() << std::endl;
    }
    return 0;
}
Last edited on
Just setting on the bench not being disturbed it sometimes changes as much as a foot.
And how does that change manifest? As a spike?
Averaging can just turn a spike into a big bump and make any real sudden change into a slope so giving again an incorrect representation of distance in a rotating sonar device (or rotating robot base).
Last edited on
CodeWriter
I have been doing some other work but am back for a bit. I was having difficulty getting the Uno to reading again so I reloaded the program from the instructable by Jsvestor. It runs again and the float is not so bad now as it is only moving about 4 cm as it sets there running. It is saying it is 178 cm to the ceiling from my desk. If I move my hand in front of the sensor it reads the difference ok. earlier it was reading any where from 170 to 186 on its whim. That was why I wanted to know how to do a smoothing on the answer.

I still want to know how to wright one simply. I think it should not matter if you needed to do a smoothing from 10 or a 1000 readings if the code was the same. Just change the number of readings to smooth out. Maybe I am just thinking too simplistic for the answer to make sense. If you average 10 readings it should make the changes less and smooth out a curve. I kinda expected to find out it was a standard function even. I will endever to wright one.


Booradley60
I do not understand what your code is doing. It looks to me like your only using 2 readings so I must not be able to follow what you wrote. I will study your code more later so I can try to understand it better.

This is the code of jsvestor that I am using. I hope it is not wrong to post it here. It is from his instructable.

code
/*
HC-SR04 Ping distance sensor]
VCC to arduino 5v GND to arduino GND
Echo to Arduino pin 13 Trig to Arduino pin 12
Red POS to Arduino pin 11
Green POS to Arduino pin 10
560 ohm resistor to both LED NEG and GRD power rail
More info at: http://goo.gl/kJ8Gl
Original code improvements to the Ping sketch sourced from Trollmaker.com
Some code and wiring inspired by http://en.wikiversity.org/wiki/User:Dstaub/robotcar
*/

#define trigPin 13
#define echoPin 12
#define led 11
#define led2 10

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(led, OUTPUT);
pinMode(led2, OUTPUT);
}

void loop() {
long duration, distance;
digitalWrite(trigPin, LOW); // Added this line
delayMicroseconds(2); // Added this line
digitalWrite(trigPin, HIGH);
// delayMicroseconds(1000); - Removed this line
delayMicroseconds(10); // Added this line
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;
if (distance < 4) { // This is where the LED On/Off happens
digitalWrite(led,HIGH); // When the Red condition is met, the Green LED should turn off
digitalWrite(led2,LOW);
}
else {
digitalWrite(led,LOW);
digitalWrite(led2,HIGH);
}
if (distance >= 200 || distance <= 0){
Serial.println("Out of range");
}
else {
Serial.print(distance);
Serial.println(" cm");
}
delay(500);
}
/code

you can change the readout to be in inches if you change the distance calculation to use 72 or 76 I forget which and change the last print line to (in) instead of (cm)
Some time ago I bought an Arduino kit but haven't got around to playing with it yet. I will have to buy a few of those hc-sr04 sonar devices as well.

My view, based on actual experience, is that averaging may not be what you really need. It is easy enough to do and I can write a less formal example than Booradley60's version tonight if you want. However I suspect you only need take three readings and replace the middle reading with the closest of the other two readings. Also there are probably better forums dedicated the Uno where all this has been done by others.

I think you will like to play with he Arduino stuff. Adafruit is a really good learning site. They sell lots of sensors and have code to operate them.

I realize it is not really important in the project I am doing. But I am wanting to learn how to do this. I am sure I will want to do this again in the future. Sensors are notorious for being sorta unstable. Even when I was being an instrument tech and trying to calibrate some of the really bad ones I wished for a way to stabilize readings. Now I am trying to learn C++ and I thought it would be a thing I could learn easily to do. I am studing the K&R C++ ver 4. It takes a while to learn this stuff.
Last edited on
Topic archived. No new replies allowed.