首页 > 编程语言 >十大滤波(C++版)

十大滤波(C++版)

时间:2024-06-03 15:02:50浏览次数:13  
标签:cout 十大 int 滤波 C++ vector rst data

在翻阅了网上多个版本的滤波算法,发现很多仍停留在多年以前,很多版本的更替没有完成。

自己和小伙伴研究了一下,研究成果如下,因为都是比较浅显的研究,如果有不符合常理的地方,请大家指出,一起进步。

一、限幅滤波

#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
//限幅滤波:设置一个幅值,当相邻的两个数据之差的绝对值大于该幅值,则认为新数据无效,用旧数据(有效数据)覆盖掉新数据(无效数据),循环这个过程,直到数组结束。
//old_value用来存储原数据,rst存储滤波结果,limit是设定的幅值
void limite_filter(vector<int> &old_value, vector<int> &rst, double limit){
    rst.push_back(old_value[0]);                                                //给rst一个初始参考值
    for(int i = 1; i < old_value.size(); i++){                                    //利用循环将数组遍历
        if((abs(old_value[i] - rst[i-1])) >= limit)                                //判断相邻两数据差值是否超过幅值
        {
            rst.push_back(rst[i - 1]);                                            //超过则用老数据覆盖新数据
        }
        else
        {
            rst.push_back(old_value[i]);                                        //未超过则将新数据存入
        }
    }                                                                            
}
//滤波过后原数据不变,滤波数据存储在rst容器中
// 测试限幅滤波功能
void test_limite_filter(){
    vector<int> data1 = {55,54,53,52,51,50,55,100,50,51};
    vector<int> data2;
    double limit = 5;

    limite_filter(data1, data2, limit);

    cout << "原始数据: ";
    for(auto d : data1){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : data2){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_limite_filter();
    return 0;
}

二、中位值滤波

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//中位值滤波
//从一个数周围取n个数据,将这n个数据排序后取得中位值,将该中位值作为这个点的滤波值
void mid_value(int N, vector<double> &data, vector<double> &rst){
    int n = data.size(), count = 0;
    while(count < n - N + 1){
        vector<double> temp(data.begin() + count, data.begin() + count + N);
        sort(temp.begin(), temp.end()); // 使用标准库函数进行排序

        if(N % 2 == 0)
            rst.push_back((temp[N / 2] + temp[(N - 1) / 2]) / 2);
        else
            rst.push_back(temp[(N - 1) / 2]);

        count++;
    }
}

// 测试中位值滤波功能
void test_mid_value(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    int N = 3;

    mid_value(N, data, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_mid_value();
    return 0;
}

三、均值滤波

#include<iostream>
#include<vector>
using namespace std;
//均值滤波与滑动滤波区别:最主要的区别:取值位置的不同,均值滤波是取N个周期的相同位置的数据进行计算,得出一个均值认定这个值为对应值。
//而滑动平均滤波是采连续的N个数,在这连续的N个数中,每次取n个数据进行处理
//n为每次处理的数据量,data中存储了所有的传入数据,rst中存储平均值
void avg(int n, vector<double> &data, vector<double> &rst){
    int size = data.size();

    for(int i = 0; i < size - n + 1; i++){
        double sum = 0;                                     // 每次计算平均值前需要将 sum 置零
        for(int j = i; j < n + i; j++){
            sum += data[j];
        }
        rst.push_back(sum / n);                             // 将平均值添加到结果数组中
    }
}

// 测试平均值滤波算法功能
void test_avg(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    int n = 3;

    avg(n, data, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "平均值: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_avg();
    return 0;
}

四、滑动平均滤波

#include<iostream>
#include<vector>
using namespace std;

//滑动平均滤波需要设置一个窗口值来确定每次进行取均值计算的数据个数,然后通过主函数中的循环调用,每次输入不同的n个数据来进行取均值处理
//N为窗口值,data为传入数据的数组,rst为存储结果的数组
void mv_avg_filter(int N, vector<double> &data, vector<double> &rst){
    int count = 0, size = data.size();                                //设置计数器,获得传入数组的大小

    while(count < size - N + 1){                                      //设置循环次数
        double sum = 0;                                               // 每次计算均值前需要将 sum 置零
        for(int i = count; i < N + count; i++){
            sum += data[i];                                           //求和
        }
        double avg = sum / N;                                         // 求均值
        rst.push_back(avg);                                           // 将求得的均值添加到 rst 数组中
        count++;
    }
}

// 测试滑动平均滤波功能
void test_mv_avg_filter(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    int N = 3;

    mv_avg_filter(N, data, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_mv_avg_filter();
    return 0;
}

五、防脉冲干扰平均滤波

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//输入所有数据,每次取一定数量的数据,排序后去除最大值与最小值,将剩余数据进行取均值处理,最后返回均值
//传入数据data,设置窗口值N,存储结果rst
//sum数据和,temp做排序中间值,count计数器,size传入数组的大小,avg均值
void im_int_filter(vector<double> &data, double N, vector<double> &rst){
    int sum = 0, temp = 0, count = 0, size = data.size();
    double avg;
    
    while(count < size - N + 1){                                                    //设置循环次数
        vector<double> temp_data(data.begin() + count, data.begin() + count + N);    //使用data数组的指针来初始化temp_data
        sort(temp_data.begin(), temp_data.end());                                    //使用标准库函数进行排序

        for(int i = 1; i < N - 1; i++){                                                //去头去尾(去掉最大值与最小值),然后求和
            sum += temp_data[i];
        }
        avg = sum / (N - 2);                                                        //取平均值
        rst.push_back(avg);                                                            //将均值存入rst数组中,rst.push_back(avg)将avg插入到数组的尾端
        sum = 0;                                                                    // 每次计算均值后需要将 sum 置零
        count++;
    }
}

// 测试滤波功能
void test_im_int_filter(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    double N = 5;

    im_int_filter(data, N, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_im_int_filter();
    return 0;
}

六、限幅均值滤波

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 限幅平均滤波函数
//data为传入数组,N为窗口值,A为限幅阈值,rst为存储结果的数组
void limit_average_filter(vector<double> &data, int N, double A, vector<double> &rst)
{
    double sum = 0;                                                    //记录滤波后的数据总和来求出最后需要的均值
    int count = 0;                                                    //计数器
    double result = 0.0;                                            //最终计算结果
    int size = data.size();                                            //得到传入数组的大小
    vector<double> arr;                                                //用来存储限幅后的数据
    arr.push_back(data[0]);                                            //赋予初值
    for(int i = count; i < count + N; i++)                            //利用循环进行限幅滤波
    {
        if( abs(arr[i] - data[i+1]) < A)                            // 若当前数据与上次滤波结果之差小于阈值 A,则将当前数据存入数组
        {
            arr.push_back(data[i+1]);
        }else{                                                        //否则将上次滤波结果传入数组
            arr.push_back(arr[i]);
        }
    }
    while(count < size - N + 1){                                    //设置循环次数,开始滑动均值滤波
        for(int k = 0;k < N; k++){                                    //每次取N个值进行求均值处理
            sum += arr[k];
        }
        result = sum / N;
        rst.push_back(result);                                        //将计算结果存储到数组中
        count++;                                                    
        sum = 0;                                                    //每次循环都将sum值清零
    }
    
}

int main()
{
    // 测试数据,M为数据量
    int M = 10;
    double data[M] = {1.0, 2.0, 1.0, 0.5, 0.5, 1.0, 2.0, 0.3, 0.2, 1.2};
    // 滤波窗口大小
    int N = 5;
    //计算结果个数
    int J = M - N + 1;
    // 限制阈值
    double A = 1.0;
    // 调用限幅平均滤波函数
    vector<double> result;
    for(int i = 0; i < J; i++){
        vector<double> temp(N);
        int k = i;
        for(int j = 0; j < N; j++){
            temp[j] = data[k];
            k++;
        }
        limit_average_filter(temp, N, A, result);
    }
    // 输出滤波结果
    for(int c = 0; c < result.size(); c++){
        cout << "滤波结果为:" << result[c] << endl;
    }
    return 0;
}

七、加权平均滤波

#include<iostream>
#include<vector>
using namespace std;

//设定一个窗口值N.传入数据数组data与权重数组weight,设置结果数组rst,最后的数据结果存储到rst中
void wei_avg_fil(int N,vector<double> &data,vector<double> &weight,vector<double> &rst){
    double sum = 0;                                    //数据总和
    double sum_wei = 0,avg = 0;                        //权重总和,平均值
    int count = 0,size = data.size();                //计数器,传入数组大小
    while(count < size - N +1){                        //设定循环条件
        for(int i = count; i < N+count; i ++){        //求数据*权重的和与权重的和
            sum += data[i] * weight[i];                
//            cout << sum <<endl;
            sum_wei += weight[i];                    
        }
        avg = sum / sum_wei;                        //得到均值数据
        rst.push_back(avg);                            //将均值数据传入rst数组的尾端
        sum = 0;                                    //结果存入后将sum值清零
        sum_wei = 0;
        count++;                                    //计数器自加
    }
}

int main(){
    vector<double> data = {1.0, 2.0, 3.0, 4.0, 5.0};
    vector<double> weight = {0.5,0.4,0.3,0.2,0.1};
    vector<double> rst;

    wei_avg_fil(4, data, weight, rst);

    for(int i = 0; i < rst.size(); i++){
        cout << "经由滤波算法过滤后的结果为: " << rst[i] << endl;
    }


    return 0;
}

八、一阶低通滤波 

#include<iostream>
#include<vector>
#include<cmath> // pi的值
using namespace std;

#define pai M_PI

/*
一阶低通滤波:利用公式得出滤波系数a(a的计算方法如下:a = Ts/(Ts+RC)=Ts/(Ts+1/(2πfc))=2πfcTs/(2πfcTs+1)
a的范围为[0,1]),然后利用两个数据(一般一个数据是上次测量或计算得出数据,用old_value来表示,一个为本次试验得到的数据,
用new_value)来进行滤波后数值的计算,然后将数值存入old_value中,计算方法如下:old_value=a * old_value+(1-a)new_value或old_value=anew_value+(1-a)*old_value,
使用哪种算法需要根据a的具体值来进行判断,一般认为,old_value数据更为准确,所以该数据占比会大一些,因此,a与1-a中,占比大的一方来处理old_value。
*/
// 一阶低通滤波函数,alpha为一阶低通滤波系数,Fc为截止频率,Ts为采样周期
double GetAlpha(double fc, double ts){
    double alpha = 2*pai*fc*ts/(2*pai*fc*ts+1);                                        //利用公式计算出滤波系数,也可以直接设置滤波系数
    return alpha;
}

// Function to perform low pass filtering
void low_pass_filtering(double alpha, vector<double> &old_value,vector<double> &rst){
    int size = old_value.size();
    rst.push_back(old_value[0]);
    for(int i = 0; i < size - 1; i++){
        if(alpha > 0.5){
            rst.push_back(alpha * old_value[i] + (1-alpha) * old_value[i+1]);        //一般将旧数据所占比重设置的较大,故公式会根据滤波系数的大小而产生变化
        }else{
            rst.push_back(alpha * old_value[i+1] + (1-alpha) * old_value[i]);
        }
    }
}


void run_test_cases(){
    vector<double> test_data1 = {1, 2, 3, 4, 5};
    vector<double> rst;
    double alpha1 = GetAlpha(5, 0.2);
    low_pass_filtering(alpha1, test_data1,rst);

    cout << "第一个测试结果:" << endl;
    for(int i = 0; i < rst.size(); i++){
        cout << rst[i] << " ";
    }
    cout << endl;

    vector<double> test_data2 = {5, 4, 3, 2, 1};
    vector<double> rst1;
    double alpha2 = GetAlpha(10, 0.1);
    low_pass_filtering(alpha2, test_data2,rst1);

    cout << "第二个测试结果:" << endl;
    for(int i = 0; i < rst1.size(); i++){
        cout << rst1[i] << " ";
    }
    cout << endl;
}

int main(){
    run_test_cases();
    return 0;
}

九、消抖滤波

#include<iostream>
#include<vector>
using namespace std;

//消抖滤波:设置一个阈值N,将传入数据与存储数据进行对比,若传入数据与存储数据不一致,则计数器+1,否则将传入数据返回。
//当传入数据与存储数据不一致,且计数器计数大于阈值N,则将传入数据返回,将其作为新的存储数据。
//N为设置的消抖参数,data为传入的数据,rst存储结果
void De_chat_filter(int N, vector<double> &data, vector<double> &rst) {
    int count = 0,j = 0;                                //count定义计数器,j为rst的下标
    rst.push_back(data[0]);                                //定义初始值(参考值)
    for (int i = 1; i < data.size(); i++) {                //利用循环进行消抖处理
        if (data[i] != rst[j]) {                        //当传入数据与存入数据不匹配时,计数器自增,然后判断计数器是否大于设置的参数,大于参数,则将新数据传入结果数组,并将计数器置零。
            count++;                                    //计数器加一
            if (count >= N) {
                j++;
                rst.push_back(data[i]);
                count = 0;
            }
        }
        else {                                            //当传入数据与存入数据一致时,将传入数据存入结果数组,并将计数器置零
            j++;
            rst.push_back(data[i]);
            count = 0;
        }
    }
}

// 滤波函数检验
void test_De_chat_filter() {
    vector<double> data = { 2.0, 3.0, 2.0, 2.0, 3.0, 3.0, 2.0, 3.0, 2.0, 2.0 };
    vector<double> rst; // 初始化存储数据
    int N = 2; // 阈值设为2

    De_chat_filter(N, data, rst);

    cout << "原始数据:" << endl;
    for (int i = 0; i < data.size(); i++) {
        cout << data[i] << " ";
    }
    cout << endl;

    cout << "滤波后数据:" << endl;
    for (int i = 0; i < rst.size(); i++) {
        if (rst[i] != 0) {
            cout << rst[i] << " ";
        }
    }
    cout << endl;
}

int main() {
    test_De_chat_filter();
    return 0;
}

十、限幅消抖滤波

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

// 定义限幅消抖滤波函数
//N为幅值,A为消抖参数,data为原数据,rst为结果数据
void cli_den_filter(double N, double A, vector<double> &data, vector<double> &rst){
    int i = 0, j = 0, size = data.size(), count = 0;                        //i,j为循环使用参数,size为data的数据大小,count为消抖计数器
    vector<double> arr(size);                                                //定义数组来存储限幅后的数据
    arr[0] = data[0];                                                        //定义初始值
    for(i = 1; i < size; i++)                                                //利用循环得到限幅后的数据
    {
        if(abs(data[i] - arr[i - 1]) >= N){                                    // 判断信号变化是否超过阈值N,进行限幅处理
            arr[i] = arr[i-1];
        }else{
            arr[i] = data[i];
        }
    }
//    cout << endl;
    for(i = 0; i < size; i++){                                                //进行消抖滤波
        if(arr[i] != arr[i-1]){                                                // 判断是否连续A次相同,输出信号
            count ++;
            if(count >= A){                                                    //当计数器数值大于设置的参数时,将数据存入,并将计数器置零
                rst.push_back(arr[i]);
                count = 0;
            }       
        }else{                                                                //当新数据与老数据相等时,存入新数据,计数器置零
            rst.push_back(arr[i]);
            count = 0;
        }
    }
}

// 测试滤波功能
void test_cli_den_filter(){
    vector<double> data = {2.0, 7.0, 1.0, 1.0, 1.0, 1.0, 2.0};
    vector<double> rst;
    double N = 2;
    double A = 3;

    cli_den_filter(N, A, data, rst);

    cout << "输入数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "输出数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;

}

int main()
{
    test_cli_den_filter();
    return 0;

                             

滤波测试用例如下:

第一个限幅滤波算法

第二个中位值滤波算法

第三个均值滤波算法

第四个滑动平均滤波算法

第五个防脉冲干扰平均滤波

第六个限幅均值滤波算法

第七个加权平均滤波算法

第八个一阶低通滤波算法

第九个消抖滤波算法

第十个限幅消抖滤波算法

欢迎大家多多交流!

                                     
        

标签:cout,十大,int,滤波,C++,vector,rst,data
From: https://blog.csdn.net/weixin_45582252/article/details/139365869

相关文章

  • c/c++设计模式---享元模式
    引入享元模式:围棋游戏:namespace_nmsp1{enumEnumColor//棋子类型{Black,//黑White//白};structPosition//棋子位置{intm_x;intm_y;Position(inttmpx,inttmpy):m_x(tmpx),m_y(tmpy){}......
  • C++:特殊类设计和四种类型转换
    一、特殊类设计1.1不能被拷贝的类     拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。C++98:1、将拷贝构造函数与赋值运算符重载只声明不定义。(防自己人)    ......
  • Visual Studio 2022创建C/C++项目
    没想到还有能用到C/C++的时候……刚好忘记怎么用VisualStudio了,写个博客记录一下 参考——https://blog.csdn.net/Long_xu/article/details/130599633https://learn.microsoft.com/zh-cn/visualstudio/extensibility/vsix/get-started/get-tools?view=vs-2022版本:VisualS......
  • 第十五届蓝桥杯国赛C++B组文字题解
    A:合法密码暴力跑一下即可,坑点是pdf有换行,字母不算字符,最后答案是:400。B:选数概率观察到第二个分数的分母很大,猜测\((a+b+c)\times(a+b+c-1)=20910‬\)发现无整数解,于是考虑到可能被约分了,将\(20910\times2=41820\)最后得到\(a+b+c=105\)然后就......
  • 关于c++出现的易错问题
    比如我一个对象,经常操作用的指针ptr,原生指针比如ClassA*ca=;但是我要保存ca,在另一个地方操作,比如: cb=ca; 这样子是不行的,因为我要操作的是ca,而不是ca的值,为什么呢,因为ca代表这个对象,而&ca,代表的是ca的地址;我用cb可以动态的更换值,来改变不同ClassA对象;所以这里用了二级指针......
  • 带交互的卡尔曼滤滤波|一维滤波|源代码
    背景一维卡尔曼滤波的MATLAB例程,​背景为温度估计。代码介绍运行程序后,可以自己输入温度真实值:以20℃为例,得到如下的估计值​:滤波前的值和滤波后的值分别于期望值(真实值)作差,可以得到​误差​曲线图:​误差统计特性源代码程序源码下载:https://download.csdn.net/......
  • 第十五届蓝桥杯大赛软件赛国赛 C/C++ 大学 A 组 游记
    Preface前情提要:去年圈钱杯国赛游记,本来还想着今年报JAVA/PY的,结果语法一个学不懂还是去CPP组开卷了省赛很简单但因为最后一题看漏条件了还是遗憾离场,但也给了我一种今年篮球杯水的一批的刻板印象然后国赛被一堆数学题直接创飞了,但好在前面几个题还能胡几个做法出来,但FWT和神秘......
  • Re0:从零开始的C++游戏开发 【下】
    Re0:从零开始的C++游戏开发(下)这是蒟蒻观看B站upVoidmatrix的课程从零开始的提瓦特幸存者的个人笔记【自用】前言:采用适用于小白的easyx图形库。第三集提瓦特の幸存者(下)3.1用户界面实现和设计模式基础3.1.1导言假设这样一个场景:在一个游戏中,出现在你的视野中的树木......
  • Re0:从零开始的C++游戏开发【中】
    Re0:从零开始的C++游戏开发(中)这是蒟蒻观看B站upVoidmatrix的课程从零开始的提瓦特幸存者的个人笔记【自用】前言:采用适用于小白的easyx图形库。第三集提瓦特の幸存者3.1程序动画实现及角色移动在开始之前,我们应该认识到,尽管我们可以通过点线面绘制简单的画面,但是想......
  • C/C++mai函数的参数
    在C和C++编程中,main函数通常是程序的入口点,定义程序的启动方式。函数签名intmain(intargc,constchar**argv,constchar**envp)包括三个参数:argc、argv和envp。这些参数分别用于接收命令行参数和环境变量。1.intargcargc代表“argumentcount”,表示传递给程序的命令行参......