在翻阅了网上多个版本的滤波算法,发现很多仍停留在多年以前,很多版本的更替没有完成。
自己和小伙伴研究了一下,研究成果如下,因为都是比较浅显的研究,如果有不符合常理的地方,请大家指出,一起进步。
一、限幅滤波
#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;
}
滤波测试用例如下:
第一个限幅滤波算法
第二个中位值滤波算法
第三个均值滤波算法
第四个滑动平均滤波算法
第五个防脉冲干扰平均滤波
第六个限幅均值滤波算法
第七个加权平均滤波算法
第八个一阶低通滤波算法
第九个消抖滤波算法
第十个限幅消抖滤波算法
欢迎大家多多交流!