平滑算法

raj*_*jat 5 c++ algorithm signal-processing filter

我写了这段代码来平滑曲线.它在一个点旁边需要5个点并添加它们并对其求平均值.

/* Smoothing */
void smoothing(vector<Point2D> &a)
{
    //How many neighbours to smooth
    int NO_OF_NEIGHBOURS=10;
    vector<Point2D> tmp=a;
    for(int i=0;i<a.size();i++)
    {

        if(i+NO_OF_NEIGHBOURS+1<a.size())
        {
            for(int j=1;j<NO_OF_NEIGHBOURS;j++)
            {
                a.at(i).x+=a.at(i+j).x;
                a.at(i).y+=a.at(i+j).y;
            }
            a.at(i).x/=NO_OF_NEIGHBOURS;
            a.at(i).y/=NO_OF_NEIGHBOURS;

        }
        else
        {
            for(int j=1;j<NO_OF_NEIGHBOURS;j++)
            {
                a.at(i).x+=tmp.at(i-j).x;
                a.at(i).y+=tmp.at(i-j).y;
            }
            a.at(i).x/=NO_OF_NEIGHBOURS;
            a.at(i).y/=NO_OF_NEIGHBOURS;
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

但是我为每个点获得了非常高的值,而不是与前一点相似的值.形状最大化了很多,这个算法出了什么问题?

lea*_*vst 10

你在这里看到的是有限脉冲响应(FIR)滤波器的低音实现,它实现了一个boxcar窗口函数.考虑到DSP方面的问题,你需要vectorNO_OF_NEIGHBOURS相等的FIR系数过滤你的输入,每个系数的值都是1/NO_OF_NEIGHBOURS.通常最好使用既定算法而不是重新发明轮子.

这是一个非常笨拙的实现,我很快就敲定了过滤器加倍.您可以轻松修改此选项以过滤数据类型.该演示显示了上升锯功能(0,.25,.5,1)的几个周期的过滤,仅用于演示目的.它编译,所以你可以玩它.

#include <iostream>
#include <vector>

using namespace std;

class boxFIR
{
    int numCoeffs; //MUST be > 0
    vector<double> b; //Filter coefficients
    vector<double> m; //Filter memories

public:
    boxFIR(int _numCoeffs) :
    numCoeffs(_numCoeffs)
    {
        if (numCoeffs<1)
            numCoeffs = 1; //Must be > 0 or bad stuff happens

        double val = 1./numCoeffs;
        for (int ii=0; ii<numCoeffs; ++ii) {
            b.push_back(val);
            m.push_back(0.);
        }
    }    

    void filter(vector<double> &a)
    {
        double output;

        for (int nn=0; nn<a.size(); ++nn)
        {
            //Apply smoothing filter to signal
            output = 0;
            m[0] = a[nn];
            for (int ii=0; ii<numCoeffs; ++ii) {
                output+=b[ii]*m[ii];
            }

            //Reshuffle memories
            for (int ii = numCoeffs-1; ii!=0; --ii) {
                m[ii] = m[ii-1];
            }                        
            a[nn] = output;
        }
    }


};

int main(int argc, const char * argv[])
{
    boxFIR box(1); //If this is 1, then no filtering happens, use bigger ints for more smoothing

    //Make a rising saw function for demo
    vector<double> a;
    a.push_back(0.); a.push_back(0.25); a.push_back(0.5); a.push_back(0.75); a.push_back(1.);
    a.push_back(0.); a.push_back(0.25); a.push_back(0.5); a.push_back(0.75); a.push_back(1.);
    a.push_back(0.); a.push_back(0.25); a.push_back(0.5); a.push_back(0.75); a.push_back(1.);
    a.push_back(0.); a.push_back(0.25); a.push_back(0.5); a.push_back(0.75); a.push_back(1.);

    box.filter(a);

    for (int nn=0; nn<a.size(); ++nn)
    {
        cout << a[nn] << endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此行增加滤波器系数的数量,以查看逐渐更平滑的输出.只有1个滤波器系数,没有平滑.

boxFIR box(1);
Run Code Online (Sandbox Code Playgroud)

代码足够灵活,您甚至可以根据需要更改窗口形状.通过修改构造函数中定义的系数来完成此操作.

注意:这将为您的实现提供略有不同的输出,因为这是一个因果过滤器(仅取决于当前样本和以前的样本).您的实现不是因果关系,因为它在未来的样本中及时展望以获得平均值,这就是为什么您需要条件语句来处理接近矢量末尾的情况.如果你想要输出就像你试图用你的过滤器一样使用这个算法,那么通过这个算法反向运行你的向量(只要窗口函数是对称的,这个工作正常).这样你就可以得到类似的输出而没有讨厌的条件部分算法.


sar*_*dok 3

在以下块中:

            for(int j=0;j<NO_OF_NEIGHBOURS;j++)
            {
                a.at(i).x=a.at(i).x+a.at(i+j).x;
                a.at(i).y=a.at(i).y+a.at(i+j).y;
            }
Run Code Online (Sandbox Code Playgroud)

对于每个邻居,您分别将 a.at(i)'sx 和 y 添加到邻居值。

我理解正确,应该是这样的。

            for(int j=0;j<NO_OF_NEIGHBOURS;j++)
            {
                a.at(i).x += a.at(i+j+1).x
                a.at(i).y += a.at(i+j+1).y
            }
Run Code Online (Sandbox Code Playgroud)