Click here to Skip to main content
15,348,004 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am not so hot at traditional math sometimes. Give me set theory and lambda calculus please!

I am trying to basically downsample some data I am receiving in real time.

I sample it initially at 10Hz but then I need to downsample the data to 1Hz

What I have tried:

I'm trying to take each incoming point I read and average it with the next. Every 10 points I start over

It's something like:
C++
float _interpolateX=readNextPoint();
int _interpolationCount=0;
void loop() {
   if(!_interpolateX) {
       _interpolateX = readNextPoint();
   } else {
       float data = readNextPoint();
      _interpolateX = (_interpolateX + data) /2;
   }

   ++_interpolationCount;
   if(10==_interpolationCount) {
      _interpolationCount = 0;
      _interpolateX=0;
   }

}


forgive the code as I had to type it from memory because last night i accidentally overwrote it without saving a copy. I haven't compiled and run the above but it's pretty close to the original. My goal is to illustrate the concept.

It's possible that I'm doing this correctly and I just don't like the result.

I wrote this in C++ but if you can read it I'll take any language in the answer
Posted
Updated 29-Nov-20 6:46am

I think what you are trying to calculate is a moving average. In any case, I don't think you can add and divide by two to get the right answer
e.g.
What you want is : (7+ 5 + 9 + 4 + 3)/5 = 5.6
What you are calculating (((((0+7)/2 + 5)/2 + 9)/2 _4)/2 +3)/2 = 4.156


Take a look at the wikipedia page for maving average and see if that helps you
Moving average - Wikipedia[^]
   
v2
Comments
honey the codewitch 29-Nov-20 11:47am
   
Thank you!
Here's a template class I wrote a while ago I call a WindowFilter. It is essentially a moving average as K5054 mentioned previously. In your case, you could set the size of the window to be 10 and it will give you the average of the last 10 samples. Best of luck with it.
C++
//
// WindowFilter.h - a filter that obtains the mean of a 'window' of data.
//                  The window of data is kept in a circular buffer.
//                  The buffer can be big as desired.  Data is not shifted.
//                  The oldest data is replaced.
//
// By Rick York - a fan of codeproject.com
//

#pragma once
#define WINDOWFILTER_H
// #include "WindowFilter.h"   // for copy-paste assistance

#include <vector>

template< typename T >
class WindowFilter
{
public:
    WindowFilter( int size=8 )
    {
        Resize( size );
    }

    void Resize( int newsize )
    {
        int sizenow = (int) m_Data.size();
        if( newsize == sizenow )
            return;

        T newval = 0;
        m_Data.resize( newsize, newval );
        if( m_Count > newsize )
            m_Count = newsize;

        m_Sum = 0;
        for( int n = 0; n < m_Count; ++n )
            m_Sum += m_Data[ n ];

        if( m_Last >= m_Count )
            m_Last = m_Count - 1;
    }

    T Add( T newvalue )
    {
        int datasize = (int) m_Data.size();
        int index = 0;
        if( m_Count != 0 )
        {
            index = m_Last + 1;
            if( index >= datasize )
                index = 0;
        }

        // remove the oldest one from the buffer

        T lastvalue = m_Data[ index ];
        m_Sum -= lastvalue;

        m_Data[ index ] = newvalue;
        m_Sum += newvalue;
        m_Last = index;

        if( m_Count < datasize )
            ++m_Count;

        return Result();
    }

    T Result() const
    {
        return m_Count ? m_Sum / m_Count : 0;
    }

public:
    using vdata = std::vector< T >;

    vdata       m_Data;
    T           m_Sum       { 0 };      // sum of data in buffer
    int         m_Count     { 0 };      // number of samples
    int         m_Last      { -1 };     // the last one loaded
};

using dwinfilter = WindowFilter< double >;
using fwinfilter = WindowFilter< float >;
   
v4
Comments
honey the codewitch 29-Nov-20 12:48pm
   
Hey thanks. This is awesome! You don't mind if I use a derivative of this code in a commercial gadget do you?
Rick York 29-Nov-20 14:09pm
   
Not at all.
C++
 float data = readNextPoint();
_interpolateX = (_interpolateX + data) /2; // last data is half the final result

I would rewrite the code like:
C++
float _interpolateX=0;
int _interpolationCount=0;
while(1) {
    _interpolateX=0;
    for (_interpolationCount=0;_interpolationCount<10;_interpolationCount++) {
        _interpolateX += readNextPoint(); // read data
    }
    _interpolateX = _interpolateX /10.0; // calc mean of 10 read
    // save down sampled data here
}
   
v2
Comments
honey the codewitch 29-Nov-20 9:23am
   
I can't do it that way because readNextPoint() reads from flash which is very slow. I need to do it one sample at a time to keep things running smoothly, if I can at all.

Therefore if my solution gets me the same as your solution I prefer my way. I actually endeavored to avoid doing it the way you do.

I should add that the number of points is compile-time configurable depending on the defined resolutions so sometimes that loop might be much larger. =)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900