常见的滤波算法及其在单片机中的应用介绍(二)

电子说

1.3w人已加入

描述

01

中值滤波

原理

中值滤波是一种非线性滤波算法,它将信号中的每个采样点替换成该采样点邻域内的中值。它的主要思想是通过找到邻域内的中值来消除信号中的噪声,同时尽可能地保留信号中的有用信息。

中值滤波的步骤如下:

a. 定义邻域大小和形状。常用的邻域形状有矩形、圆形、十字形等。

b. 对信号的每个采样点,选取其邻域内的所有采样点,并将其排序。

c. 将排序后的采样点序列中间的值作为该采样点的输出值。

由于中值滤波采用了排序的方式,因此它比线性滤波算法的计算量要大,但是相对于其它非线性滤波算法,中值滤波的计算量相对较小,而且不需要预先确定滤波器参数,因此具有很好的实时性能。

中值滤波通常适用于以下场景:

a. 信号中含有脉冲噪声或椒盐噪声。

b. 信号中含有高斯噪声,但信号的均值和方差不易确定。

c. 信号中含有周期性噪声,周期长度大于邻域大小。

需要注意的是,中值滤波可能会导致信号的某些特征被模糊化,因此在应用中需要谨慎选择邻域大小和形状,以及滤波器的使用场景。

代码

下面是一个使用C语言编写的中值滤波函数的示例代码,它可以处理一个长度为N的整型数组input,并将输出结果保存在一个长度为N的整型数组output中。这个函数的邻域大小由变量size指定,可以根据需要进行调整。

C++
#include
#include

#define SIZE 3 // 邻域大小

int cmp(const void *a, const void b) {
return (
(int *)a - *(int *)b);
}

void median_filter(int *input, int *output, int N) {
int i, j, k, m;
int median[SIZE * SIZE];

for (i = 0; i < N; i++) {
    k = 0;
    for (j = i - (SIZE - 1) / 2; j <= i + (SIZE - 1) / 2; j++) {
        if (j < 0 || j >= N) {
            continue;
        }
        for (m = j - (SIZE - 1) / 2; m <= j + (SIZE - 1) / 2; m++) {
            if (m < 0 || m >= N) {
                continue;
            }
            median[k++] = input[m];
        }
    }
    qsort(median, k, sizeof(int), cmp);
    output[i] = median[k / 2];
}

}

int main() {
int input[] = {1, 5, 2, 7, 3, 9, 4, 8, 6};
int output[sizeof(input) / sizeof(int)];
int N = sizeof(input) / sizeof(int);
int i;

median_filter(input, output, N);

printf("Input data: ");
for (i = 0; i < N; i++) {
    printf("%d ", input[i]);
}
printf("n");

printf("Output data: ");
for (i = 0; i < N; i++) {
    printf("%d ", output[i]);
}
printf("n");

return 0;

}

输出结果如下:

Kotlin
Input data: 1 5 2 7 3 9 4 8 6
Output data: 2 2 3 4 4 5 6 7 8

可以看到,中值滤波算法可以有效地消除噪声,同时尽可能地保留原始信号的特征。需要注意的是,在使用中值滤波算法时,邻域大小的选择需要根据实际情况进行调整,以免产生过度平滑或者信息损失的问题。

02

消抖滤波

原理

消抖滤波法(Debouncing Filter)是一种常用的信号处理算法。它主要用于消除由于输入信号在短时间内出现了快速变化而导致的抖动现象。在实际应用中,如电子开关、按键等场景中,由于机械接触的原因,可能会产生短时间内快速变化的信号,这种信号称为抖动信号,会对系统产生误判和误动作。因此,需要对这种信号进行滤波处理。

消抖滤波法的基本思想是在输入信号发生变化时,延迟一段时间再检测信号状态,如果信号保持稳定状态,则认为信号有效。如果信号在这段时间内发生了变化,则重新计时。这种方法可以有效地抑制抖动信号,并且可以消除无效的信号瞬态。

消抖滤波法的具体实现方式可以采用软件或硬件的方式实现。软件实现方式常见的是利用定时器进行延时,硬件实现方式常见的是利用RC电路进行延时。下面给出一个基于软件实现的消抖滤波函数的伪代码:

Python
int debouncing_filter(int input, int delay_ms) {
static int last_input = 0;
static int stable_cnt = 0;
if (input != last_input) {
stable_cnt = 0;
}
else {
stable_cnt++;
}
last_input = input;
if (stable_cnt >= delay_ms / sampling_time) {
return input;
}
else {
return last_input;
}
}

在这个函数中,input表示输入信号的状态,delay_ms表示需要延迟的时间。函数通过记录上一个时刻的输入状态以及信号保持稳定状态的时间来实现消抖功能。如果信号保持稳定状态的时间超过了设定的延时时间,则返回当前的输入状态。否则,返回上一个时刻的输入状态。

需要注意的是,在使用消抖滤波法时,延时时间需要根据具体的应用场景来进行设置。如果延时时间设置过长,则可能会导致信号响应时间过长,影响系统的实时性;如果延时时间设置过短,则可能会无法有效地抑制抖动信号。

代码

下面给出一个基于软件实现的消抖滤波函数的具体实现代码,以及使用示例:

C++
int debouncing_filter(int input, int delay_ms) {
static int last_input = 0;
static int stable_cnt = 0;
if (input != last_input) {
stable_cnt = 0;
}
else {
stable_cnt++;
}
last_input = input;
if (stable_cnt >= delay_ms / 10) { // 采样周期假设为10ms
return input;
}
else {
return last_input;
}
}

在这个函数中,input表示输入信号的状态,delay_ms表示需要延迟的时间。函数通过记录上一个时刻的输入状态以及信号保持稳定状态的时间来实现消抖功能。如果信号保持稳定状态的时间超过了设定的延时时间,则返回当前的输入状态。否则,返回上一个时刻的输入状态。

下面给出一个示例,展示如何使用该函数进行消抖处理:

C++
#include

int main() {
int input = 0;
int output = 0;
int delay_ms = 50; // 延时时间为50ms
while (1) {
scanf("%d", &input); // 从终端读取输入信号状态
output = debouncing_filter(input, delay_ms); // 进行消抖滤波处理
printf("Input: %d, Output: %dn", input, output); // 输出结果
}
return 0;
}

在这个示例中,首先从终端读取输入信号状态,然后调用debouncing_filter函数进行消抖滤波处理,并将处理后的结果输出到终端。循环执行该过程,直到程序结束。

03

递推平均滤波

原理

递推平均滤波法,又称为滑动平均滤波法,是一种对于输入信号进行平滑处理的算法。该算法采用一定的方式对一定数量的输入信号进行加权平均,得到一个平滑的输出信号。具体地,递推平均滤波法使用一个固定长度的窗口,每当有新的输入信号到来时,就将窗口内的旧的信号淘汰掉,并将新的信号加入到窗口中,然后重新计算窗口内所有信号的平均值作为当前的输出信号。

因此,随着新的信号不断到来,窗口内的信号会不断滑动,而输出信号也会不断变化,从而实现对输入信号的平滑处理。

递推平均滤波法的优点是简单、实时性好,对于周期性的噪声有一定的抑制效果。其缺点是在处理突变的输入信号时,输出信号会有一定的延迟,且在窗口大小不够大的情况下,噪声的抑制效果会比较有限。

下面是递推平均滤波法的算法步骤:

a. 定义一个固定长度为N的窗口,并初始化窗口内的所有数据为0。

b. 当有新的输入信号x_i到来时,将窗口内的第一个信号x_{i-N}移除,并将新的信号x_i加入到窗口中。

c. 计算窗口内所有信号的平均值,作为当前的输出信号y_i。

d. 返回输出信号y_i,并等待下一次输入信号到来。

代码

下面是递推平均滤波法的示例代码,其中,N为窗口大小,x表示输入信号,y表示输出信号,buffer为窗口缓存,sum为窗口内数据的累加和:

C++
#define N 10 // 窗口大小

float moving_average_filter(float x) {
static float buffer[N] = {0};
static float sum = 0;
static int ptr = 0;
sum = sum - buffer[ptr] + x;
buffer[ptr] = x;
ptr = (ptr + 1) % N;
return sum / N;
}

在这个函数中,我们使用了一个静态的窗口缓存buffer来存储窗口内的数据,使用sum来记录窗口内数据的累加和,使用ptr来记录当前窗口内最后一个数据的位置。当有新的输入信号x到来时,我们将窗口内第一个数据buffer[ptr-N]移除,并将新的信号x加入到窗口中。然后,我们重新计算窗口内所有信号的平均值作为当前的输出信号,并将作为当前的输出信号,返回输出信号,并等待下一次输入信号到来。

04

中位值平均滤波法

原理

中位值平均滤波法是一种抗干扰性能很强的滤波方法,也称为防脉冲干扰平均滤波法。与其他滤波方法不同的是,它不是对一段时间内的数据进行简单的平均处理,而是将一段时间内的多个数据进行排序,然后取中间值作为滤波结果。中位值平均滤波法的优点是可以有效地滤除脉冲噪声、斜坡干扰等干扰信号。

中位值平均滤波法的实现步骤如下:

a. 将一段时间内的多个数据存储在数组中;

b. 对数组进行排序;

c. 取排序后中间位置的数值作为滤波结果。

中位值平均滤波法的实现较为简单,但由于需要对数组进行排序,计算量较大,因此在实际应用中需要注意性能问题。

中位值平均滤波法的优点:

a. 对脉冲噪声、斜坡干扰等干扰信号具有较强的滤除能力;

b. 滤波效果较好,能够保持信号的较高精度。

中位值平均滤波法的缺点:

a. 计算量较大,特别是在大数据量时;

b. 无法完全消除高频噪声,因此在高频噪声较多的情况下效果可能不佳;

c. 数组排序会改变原始数据的顺序,因此需要注意排序的实现方式,避免对实际应用造成影响。

代码

C++
#include

// 中位值平均滤波函数
int Median_Filter(int *data, int length)
{
int i, j, temp, result;
int *sort = (int *)malloc(sizeof(int) * length); // 分配排序数组的空间
memcpy(sort, data, sizeof(int) * length); // 复制原始数据到排序数组

// 冒泡排序
for (i = 0; i < length - 1; i++) {
    for (j = i + 1; j < length; j++) {
        if (sort[i] > sort[j]) {
            temp = sort[i];
            sort[i] = sort[j];
            sort[j] = temp;
        }
    }
}

// 取中间值作为滤波结果
result = sort[length / 2];

// 释放排序数组的空间
free(sort);

return result;

}

int main()
{
int data[10] = {5, 6, 8, 9, 12, 7, 13, 10, 11, 6};
int result;

result = Median_Filter(data, 10);
printf("Filtered result: %dn", result);

return 0;

}

上面的程序实现了一个简单的中位值平均滤波函数Median_Filter,该函数的参数data为原始数据数组,length为数据数组的长度。函数返回经过中位值平均滤波后的结果。

在main函数中,我们声明了一个长度为10的原始数据数组data,并将其传递给Median_Filter函数进行中位值平均滤波。最后输出滤波后的结果。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分