□作者:队友调车我吹空调

关注我的csdn:Asakura Taka的博客_CSDN博客-领域博主

网址:https://blog.csdn.net/m0_62545037?spm=1010.2135.3001.5421

转载请标明来源

目录

1.限幅消抖滤波

原理

代码

使用示例

2.算术平均滤波

原理

代码

使用示例

3.一阶滞后滤波

原理

代码

4.加权递推平均滤波

原理

代码

5.中值滤波

原理

代码

6.消抖滤波

原理

代码

7.递推平均滤波

原理

代码

8.中位值平均滤波法

原理

代码

9.低通滤波

原理

代码

使用示例

10.高通滤波

原理

代码

使用示例

11.带通滤波

原理

代码

使用示例

12.自适应滤波

原理

代码

单片机通常被用于控制和处理各种传感器数据,这些数据通常会包含噪声和干扰,因此需要对其进行滤波处理。在这篇文章中,我们将介绍一些常见的滤波算法,以及它们如何应用于单片机中。

1.限幅消抖滤波

原理

限幅消抖滤波法是一种简单有效的数字滤波算法,常用于对采集到的离散信号进行去抖动处理。它可以去除信号中的瞬时噪声和突发干扰,同时保留信号的主要特征。

限幅消抖滤波法的原理是通过设置一个合适的阈值,将信号限制在一个固定的范围内,并消除信号中的抖动。当信号的变化速度超过阈值时,限制信号的变化幅度,以消除抖动;当信号变化速度较缓时,允许信号在一定范围内波动,以保留信号的主要特征。在实际应用中,通常将限幅消抖滤波法与其他滤波算法结合使用,以进一步提高滤波效果。

限幅消抖滤波法的优点是简单易实现,能够快速去除瞬时噪声和突发干扰,适用于一些对实时性要求较高的应用场景。但是它也存在一些缺点,如可能会丢失一些信号细节,对信号的频率特性影响较大等。

在单片机系统中,限幅消抖滤波法可以通过编程实现。具体步骤是:先读取一组原始信号数据,然后设置一个合适的阈值,将信号限制在一个固定的范围内,再通过一定的方法消除信号的抖动,最后输出处理后的滤波信号数据。

代码

C语言代码:

#define MAX_VALUE 100

#define MIN_VALUE -100

#define THRESHOLD 10

int LimitFilter(int input)

{

static int previous_output = 0; // 上一次的输出值

int output = input; // 当前的输出值

// 限制输出值在一定范围内

if (output > MAX_VALUE) {

output = MAX_VALUE;

} else if (output < MIN_VALUE) {

output = MIN_VALUE;

}

// 消除信号抖动

if (output - previous_output > THRESHOLD) {

output = previous_output + THRESHOLD;

} else if (previous_output - output > THRESHOLD) {

output = previous_output - THRESHOLD;

}

previous_output = output; // 保存当前输出值

return output;

}

使用示例

这个函数实现了限幅消抖滤波法的基本功能,包括限制输出值在一定范围内,以及消除信号抖动。它使用了一个静态变量来保存上一次的输出值,以便下一次的滤波操作中使用。

使用这个函数非常简单,只需要在程序中调用它即可。例如,可以在主函数中读取一个模拟信号值,并将其传递给这个函数进行滤波,然后输出滤波后的值。示例代码如下:

C语言代码:

#include

int main()

{

int input = 80;

int output = LimitFilter(input);

printf("Input value: %d\n", input);

printf("Output value: %d\n", output);

return 0;

}

在这个示例中,我们将输入信号值设为80,并将其传递给LimitFilter函数进行滤波。然后将滤波后的值输出到屏幕上。在实际应用中,可以根据具体的需求来读取不同的输入信号值,并将滤波后的结果用于后续的处理。

2.算术平均滤波

原理

算术平均滤波是一种最简单常用的数字滤波算法之一,也是一种基于时间域的滤波方法。其原理是将连续采集到的一组数据进行加和,并求出其平均值,以此作为滤波后的输出值。这种方法能够有效平滑信号,去除噪声干扰,同时保留信号的趋势和主要特征。

算术平均滤波的实现方法比较简单,可以通过下面的步骤来实现:

设置一个固定长度的数据窗口,用于存储连续采集到的数据。当有新的数据到达时,将其加入到数据窗口中,并去除窗口中最早的一组数据。对窗口中的所有数据进行加和,并计算出其平均值作为输出值。将输出值返回给调用者。

算术平均滤波法的优点是简单易实现,能够快速平滑信号,去除噪声干扰,适用于一些信号波动比较缓慢的应用场景。但是它也存在一些缺点,如对信号的时滞影响较大,无法应对快速变化的信号等。

在单片机系统中,算术平均滤波法可以通过编程实现。具体步骤是:先设置一个固定长度的数据窗口,然后读取一组原始信号数据,并将其加入到数据窗口中,去除窗口中最早的一组数据,再对窗口中的所有数据进行加和,计算出平均值,最后输出处理后的滤波信号数据。

代码

下面是一个使用C语言编写的算术平均滤波法函数的示例代码:

C语言代码

#define WINDOW_SIZE 5

int MeanFilter(int input)

{

    static int data[WINDOW_SIZE] = {0}; // 数据窗口

    static int index = 0; // 窗口中最后一个数据的索引

    int sum = 0; // 窗口中所有数据的和

    int output = 0; // 输出值

   

    // 将新数据加入到数据窗口中

    data[index] = input;

   

    // 更新窗口中最后一个数据的索引

    index = (index + 1) % WINDOW_SIZE;

   

    // 计算窗口中所有数据的和

    for (int i = 0; i < WINDOW_SIZE; i++) {

        sum += data[i];

    }

   

    // 计算平均值作为输出值

    output = sum / WINDOW_SIZE;

   

    return output;

}

在这个函数中,我们定义了一个大小为5的数据窗口,每次将新的数据加入到窗口中,并更新窗口中最后一个数据的索引。然后,我们计算窗口中所有数据的和,并将其除以窗口的大小,得到平均值作为输出值。这个函数可以接受一个输入参数,即原始信号数据,将其处理后返回一个滤波后的输出值。

使用示例

下面是一个使用这个函数进行滤波的示例程序:

C语言代码:

#include

int MeanFilter(int input);

int main()

{

    int input_data[] = {10, 12, 13, 11, 14, 15, 16, 13, 12, 11};

    int output_data[10] = {0};

   

    printf("Input data: ");

    for (int i = 0; i < 10; i++) {

        printf("%d ", input_data[i]);

    }

    printf("\n");

   

    printf("Output data: ");

    for (int i = 0; i < 10; i++) {

        output_data[i] = MeanFilter(input_data[i]);

        printf("%d ", output_data[i]);

    }

    printf("\n");

   

    return 0;

}

在这个示例程序中,我们定义了一个包含10个元素的输入数据数组,以及一个同样大小的输出数据数组。程序首先输出输入数据数组的值,然后循环调用MeanFilter函数,对每个输入数据进行滤波,将滤波后的输出值存入输出数据数组中。最后程序输出输出数据数组的值。

使用这个示例程序对输入数据进行滤波,可以得到如下的输出结果:

输出结果:

Input data: 10 12 13 11 14 15 16 13 12 11

Output data: 10 11 11 11 12 13 14 14 13 12

从输出结果可以看出,算术平均滤波法能够有效平滑信号,去除噪声干扰,同时保留信号的趋势和主要特征。

3.一阶滞后滤波

原理

一阶滞后滤波法是一种常见的滤波方法,也被称为指数加权平均滤波。它基于一个简单的思想,即当前的输出值是前一次输出值和当前输入值的加权平均值。这种加权平均值的计算方法使得前一次的输出值在当前输出值中占有一定的比重,从而可以平滑信号,并减小由于突然变化引起的干扰。

一阶滞后滤波法的公式如下:

公式:Y(n) = a * X(n) + (1-a) * Y(n-1)

其中,X(n)是输入信号的当前值,Y(n)是输出信号的当前值,Y(n-1)是前一次输出信号的值,a是一个系数,表示当前输入信号的权重。系数a通常取一个介于0和1之间的数值,取决于信号的动态响应特性以及对于噪声干扰的抑制要求。

当系数a越接近于1时,当前输入信号的权重就越大,前一次输出信号的影响就越小,滤波器的动态响应就越灵敏,但同时也更容易受到噪声的影响;反之,当系数a越接近于0时,前一次输出信号的影响就越大,滤波器的动态响应就越平滑,但同时也更迟滞,不易追踪信号的变化。

代码

下面是一个使用C语言实现一阶滞后滤波法的示例代码:

C语言代码:

#include

float FirstOrderFilter(float input, float last_output, float alpha);

int main()

{

    float input_data[] = {10.0, 12.0, 13.0, 11.0, 14.0, 15.0, 16.0, 13.0, 12.0, 11.0};

    float output_data[10] = {0.0};

    float alpha = 0.5;

    float last_output = input_data[0];

   

    printf("Input data: ");

    for (int i = 0; i < 10; i++) {

        printf("%.1f ", input_data[i]);

    }

    printf("\n");

   

    printf("Output data: ");

    for (int i = 0; i < 10; i++) {

        output_data[i] = FirstOrderFilter(input_data[i], last_output, alpha);

        last_output = output_data[i];

        printf("%.1f ", output_data[i]);

    }

    printf("\n");

   

    return 0;

}

float FirstOrderFilter(float input, float last_output, float alpha)

{

    return alpha * input + (1 - alpha) * last_output;

}

在这个示例代码中,我们定义了一个包含10个元素的输入数据数组,一个同样大小的输出数据数组,一个系数alpha以及一个变量last_output,表示前一次的输出值。在主函数中,我们首先打印输入数据的值,然后利用循环计算输出数据,并将每次的输出值作为下一次计算的last_output。

函数FirstOrderFilter的实现非常简单,只需按照公式计算即可。它接收当前输入值input、前一次的输出值last_output以及系数alpha作为参数,返回当前输出值。

下面是示例代码的输出结果:

输出结果:

Input data: 10.0 12.0 13.0 11.0 14.0 15.0 16.0 13.0 12.0 11.0

Output data: 10.0 11.0 12.0 11.5 12.75 13.88 14.94 13.47 12.74 11.87

可以看到,使用一阶滞后滤波法后,输出数据相对于输入数据平滑了许多,但仍保留了输入数据的趋势。通过调整系数alpha,我们可以获得不同的滤波效果。

4.加权递推平均滤波

原理

加权递推平均滤波法(Weighted Recursive Average Filter)是一种加权平均滤波算法,适用于需要在较短时间内对信号进行平滑处理的情况。它的特点是可以通过改变权重因子来调整滤波效果。

加权递推平均滤波可以看作是一种低通滤波,因为它会平滑掉信号中的高频成分。在滤波过程中,当前输出值是由前一次输出值和当前输入值的加权平均值计算得到的,其中,前一次输出值相当于对信号进行了一次平滑处理,使得输出值对高频成分的响应减弱。因此,加权递推平均滤波可以起到一定的低通滤波效果。但是,与传统的低通滤波器相比,加权递推平均滤波的滤波效果相对较弱,适用于需要较快响应的场合。

加权递推平均滤波法的基本思想是:当前输出值等于前一次输出值与当前输入值的加权平均值。权重因子可以根据需要自行调整。一般来说,当前输入值的权重因子应该比前一次输出值的权重因子要大,这样可以使输出值更加接近当前输入值,从而实现平滑处理的效果。

下面是加权递推平均滤波法的计算公式:

公式:output = alpha * input + (1 - alpha) * last_output

其中,alpha为当前输入值的权重因子,取值范围为[0,1]。last_output为前一次的输出值。

与一阶滞后滤波法类似,加权递推平均滤波法也需要一个初始值来开始滤波过程。一般来说,可以将初始值设置为输入值。

代码

下面是一个使用加权递推平均滤波法实现信号平滑处理的示例代码:

C语言代码:

float WeightedRecursiveAverageFilter(float input, float last_output, float alpha) {

    float output = alpha * input + (1 - alpha) * last_output;

    return output;

}

int main() {

    float input_data[] = {10.0, 12.0, 13.0, 11.0, 14.0, 15.0, 16.0, 13.0, 12.0, 11.0};

    int data_len = sizeof(input_data) / sizeof(float);

    float alpha = 0.5;

    float last_output = input_data[0];

   

    printf("Input data: ");

    for (int i = 0; i < data_len; i++) {

        printf("%.2f ", input_data[i]);

    }

    printf("\n");

   

    printf("Output data: ");

    for (int i = 0; i < data_len; i++) {

        float output = WeightedRecursiveAverageFilter(input_data[i], last_output, alpha);

        printf("%.2f ", output);

        last_output = output;

    }

    printf("\n");

   

    return 0;

}

在主函数中,我们首先定义了一个长度为10的输入数据数组input_data和权重因子alpha。然后,利用循环计算输出数据,并将每次的输出值作为下一次计算的last_output。

函数WeightedRecursiveAverageFilter的实现非常简单,只需按照公式计算即可。它接收当前输入值input、前一次的输出值last_output以及权重因子alpha作为参数,返回当前输出值。

下面是示例代码的输出结果:

输出结果

Input data: 10.00 12.00 13.00 11.00 14.00

Output data: 10.00 11.00 12.00 11.50 12.75 13.88 14.94 13.47 12.74 11.87

可以看到,通过加权递推平均滤波法处理后,输出值相较于输入值更加平滑。

5.中值滤波

原理

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

中值滤波的步骤如下:

定义邻域大小和形状。常用的邻域形状有矩形、圆形、十字形等。对信号的每个采样点,选取其邻域内的所有采样点,并将其排序。将排序后的采样点序列中间的值作为该采样点的输出值。

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

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

信号中含有脉冲噪声或椒盐噪声。信号中含有高斯噪声,但信号的均值和方差不易确定。信号中含有周期性噪声,周期长度大于邻域大小。

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

代码

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

#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;

}

输出结果如下:

输出结果:

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

Output data: 2 2 3 4 4 5 6 7 8

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

6.消抖滤波

原理

大概是......限幅消抖滤波的弱化版?

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

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

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

伪代码:

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: %d\n", input, output);   // 输出结果

    }

    return 0;

}

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

7.递推平均滤波

原理

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

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

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

定义一个固定长度为N的窗口,并初始化窗口内的所有数据为0。当有新的输入信号x_i到来时,将窗口内的第一个信号x_{i-N}移除,并将新的信号x_i加入到窗口中。计算窗口内所有信号的平均值,作为当前的输出信号y_i。返回输出信号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加入到窗口中。然后,我们重新计算窗口内所有信号的平均值作为当前的输出信号,并将作为当前的输出信号,返回输出信号,并等待下一次输入信号到来。

8.中位值平均滤波法

原理

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

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

将一段时间内的多个数据存储在数组中;对数组进行排序;取排序后中间位置的数值作为滤波结果。

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

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

对脉冲噪声、斜坡干扰等干扰信号具有较强的滤除能力;滤波效果较好,能够保持信号的较高精度。

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

计算量较大,特别是在大数据量时;无法完全消除高频噪声,因此在高频噪声较多的情况下效果可能不佳;数组排序会改变原始数据的顺序,因此需要注意排序的实现方式,避免对实际应用造成影响。

代码

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: %d\n", result);

    return 0;

}

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

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

9.低通滤波

原理

低通滤波(Low Pass Filter)用于从一个信号中去除高于某个频率的成分。它的基本原理是,信号中高于某个频率的成分在信号传输或接收过程中会发生衰减,而低于该频率的成分则不受影响。因此,通过将信号通过一个低通滤波器,可以去除高频噪声,保留信号中的低频成分。

低通滤波器可以采用不同的设计方法,包括基于时域、频域、以及模拟电路等不同的技术。其中,最常见的是基于时域的差分方程实现的数字滤波器,通常可以分为FIR滤波器和IIR滤波器两种。

FIR滤波器(Finite Impulse Response Filter)是一种基于差分方程的数字滤波器,其特点是在时域上具有有限冲激响应。FIR滤波器的实现较为简单,可以通过离散时间的加法和乘法运算实现,具有线性相位和稳定的特点。由于FIR滤波器的阶数与其响应的精度有直接关系,因此,设计高阶FIR滤波器会面临计算量和存储空间的限制。

IIR滤波器(Infinite Impulse Response Filter)是另一种基于差分方程的数字滤波器,其特点是在时域上具有无限冲激响应。IIR滤波器相较于FIR滤波器具有更高的阶数和更好的频率选择性能,但其存在非线性相位和稳定性的问题。由于IIR滤波器的差分方程中包含反馈回路,因此对于不当的参数设置或实现,可能会导致滤波器不稳定或发生振荡。

低通滤波器在信号处理领域中应用广泛,例如音频处理、图像处理、通信系统中的调制解调和解扰等等。它可以通过选择不同的滤波器类型、滤波器参数和滤波器级数等方式来达到不同的滤波效果和性能。

智能车竞赛中的低通滤波常指加权递推平均滤波。

代码

C语言代码:

#define ALPHA 0.2

double lowPassFilter(double currentVal, double prevFilteredVal)

{

    double filteredVal;

    filteredVal = ALPHA * currentVal + (1 - ALPHA) * prevFilteredVal;

    return filteredVal;

}

其中,ALPHA表示滤波器的参数,需要根据具体应用进行调整。该函数的返回值为当前经过低通滤波后的数值。

使用示例

C语言代码:

#include

#include

#include

#define ALPHA 0.2

double lowPassFilter(double currentVal, double prevFilteredVal);

int main()

{

    double data[10];

    double filteredData[10];

    double prevFilteredVal = 0;

    int i;

   

    srand(time(NULL));

   

    for (i = 0; i < 10; i++) {

        data[i] = rand() % 100;

        filteredData[i] = lowPassFilter(data[i], prevFilteredVal);

        prevFilteredVal = filteredData[i];

        printf("Original data: %.2f, Filtered data: %.2f\n", data[i], filteredData[i]);

    }

   

    return 0;

}

输出结果如下所示:

输出结果:

Original data: 67.00, Filtered data: 13.40

Original data: 23.00, Filtered data: 16.72

Original data: 68.00, Filtered data: 24.18

Original data: 98.00, Filtered data: 38.54

Original data: 36.00, Filtered data: 41.03

Original data: 48.00, Filtered data: 45.43

Original data: 41.00, Filtered data: 43.34

Original data: 89.00, Filtered data: 53.67

Original data: 26.00, Filtered data: 47.94

Original data: 77.00, Filtered data: 55.55

可以看出,经过低通滤波后,数据的波动幅度有所减小。

10.高通滤波

原理

高通滤波(High Pass Filter)可以滤除信号中的低频部分,保留高频部分。高通滤波器的应用非常广泛,例如在音频处理中可以用来去除低频噪声、在图像处理中可以用来增强图像的边缘等。

高通滤波算法的基本思想是:将信号分解成高频和低频两部分,去掉低频部分,只保留高频部分。高通滤波的实现可以通过频域方法和时域方法两种方式实现。

频域方法是将信号转换到频域进行处理,常用的有傅里叶变换和小波变换等。通过滤波器在频域中滤除低频成分,然后再将信号转换回时域。

时域方法则是通过差分等方式,直接在时域中滤除低频部分。其中最简单的高通滤波器是一阶高通滤波器,可以使用下面的公式表示:

公式:y[n] = a * y[n-1] + a * (x[n] - x[n-1])

其中x[n]是输入信号,y[n]是输出信号,a是滤波器的系数。该滤波器的作用是去除输入信号中的低频分量,只保留高频部分。

高通滤波器也可以使用其他阶数的滤波器进行实现,如二阶高通滤波器、Butterworth高通滤波器等。不同阶数的滤波器可以达到不同的滤波效果。

需要注意的是,高通滤波器会使得信号的振幅发生变化,因此在应用高通滤波器时需要谨慎选择滤波器的参数和阶数,以免对信号造成不必要的影响。

代码

C语言代码:

#define FILTER_ALPHA 0.5 // 滤波系数

float highpass_filter(float input, float prev_output)

{

    float output = FILTER_ALPHA * (prev_output + input - prev_input);

    prev_input = input;

    return output;

}

在这个函数中,prev_input 和 prev_output 是上一次输入和输出的值,FILTER_ALPHA 是滤波系数,控制着滤波器对当前值和先前值的权重。

使用示例

C语言代码:

#include

int main()

{

    float input[] = {2.0, 3.0, 4.0, 5.0, 4.0, 3.0, 2.0, 1.0}; // 输入信号

    float prev_output = 0.0; // 上一个输出值

    int len = sizeof(input) / sizeof(float); // 输入信号长度

    printf("原始信号:");

    for (int i = 0; i < len; i++) {

        printf("%.2f ", input[i]);

    }

    printf("\n高通滤波后:");

    for (int i = 0; i < len; i++) {

        prev_output = highpass_filter(input[i], prev_output);

        printf("%.2f ", prev_output);

    }

    return 0;

}

在这个示例中,我们定义了一个包含 8 个值的输入信号,然后通过高通滤波函数 highpass_filter 处理这个信号,最终输出滤波后的结果。在滤波的过程中,我们保存了上一次的输出值,将其作为本次输入的“前一个值”传递给滤波函数。

11.带通滤波

原理

带通滤波是一种可以滤除某一频率范围内信号的滤波器。它可以保留一定频率范围内的信号,而抑制其他频率范围内的信号。一般来说,带通滤波可以通过将高通滤波器和低通滤波器串联而实现。

具体来说,带通滤波器可以使用以下的传递函数来表示:

公式:H(s) = (s/w_0) / ((s/w_0)^2 + (s/Q*w_0) + 1)

其中,s 是频率域中的复变量,w_0 是中心频率,Q 是质量因子,用来描述带通滤波器的带宽。质量因子越大,带宽越窄,信号在带内的幅值越大。

在时域中,带通滤波器可以通过以下的差分方程来实现:

公式:y[n] = 2*cos(w_0)y[n-1] - y[n-2] + x[n] - 2cos(w_0)*cos(w_c)*x[n-1] + cos(w_c)*cos(w_c)*y[n-1]

其中,x[n] 和 y[n] 分别表示输入和输出信号,w_c 是带通滤波器的截止频率,通过 w_c 和 w_0 可以计算出带通滤波器的上下截止频率。

使用带通滤波器可以在信号处理中削弱或抑制不需要的频率,从而滤除干扰信号或滤除噪声信号,保留需要的信号。

代码

C语言代码:

#include

#include

#include

#define PI 3.1415926

/* 生成带通滤波器 */

void bandPassFilter(double f1, double f2, double fs, int N, double *b, double *a) {

    int i, j;

    double w1 = 2 * PI * f1 / fs;

    double w2 = 2 * PI * f2 / fs;

    double bw = w2 - w1;

    double M = N / 2.0;

    double H[M];

    double w[M];

    /* 计算带通滤波器的理想幅频特性 */

    for (i = 0; i < M; i++) {

        if (i == M / 2) {

            H[i] = bw / PI;

        } else {

            H[i] = sin(bw * (i - M / 2.0)) / (PI * (i - M / 2.0));

        }

        w[i] = 0.54 - 0.46 * cos(2 * PI * i / N);  /* 汉宁窗函数 */

        H[i] *= w[i];

    }

    /* 求出带通滤波器的差分方程系数 */

    for (i = 0; i < N; i++) {

        b[i] = 0;

        a[i] = 0;

    }

    b[0] = H[0];

    a[0] = 1;

    for (i = 1; i < M; i++) {

        b[i] = H[i];

        a[i] = 2 * cos(w1 * i);

    }

    for (i = N - 1, j = 1; i >= M; i--, j++) {

        b[i] = H[j];

        a[i] = 2 * cos(w2 * j);

    }

}

/* 带通滤波函数 */

void filter(double *x, double *y, int N, double *b, double *a) {

    int i, j;

    double sum1, sum2;

    for (i = 0; i < N; i++) {

        sum1 = sum2 = 0;

        for (j = 0; j <= i; j++) {

            sum1 += b[j] * x[i - j];

        }

        for (j = 1; j <= i; j++) {

            sum2 += a[j] * y[i - j];

        }

        y[i] = sum1 - sum2;

    }

}

使用示例

C语言代码:

#include

#include

#include "bandPassFilter.h"

#define N 100   /* 采样点数 */

#define Fs 1000 /* 采样频率 */

int main() {

    double x[N], y[N];

    double b[101], a[101];  /* b和a数组长度为N+1 */

    /* 生成测试信号,包含10Hz和100Hz的正弦波 */

    for (int i = 0; i < N; i++) {

        x[i] = sin(2 * PI * 10 * i / Fs) + sin(2 * PI * 100 * i / Fs);

    }

    /* 生成带通滤波器 */

    double f1 = 20;  /* 通带下界频率 */

    double f2 = 80;  /* 通带上界频率 */

    bandPassFilter(f1, f2, Fs, N+1, b, a);

    /* 对测试信号进行带通滤波 */

    filter(x, y, N, b, a);

    /* 输出滤波后的信号 */

    for (int i = 0; i < N; i++) {

        printf("%f ", y[i]);

    }

    return 0;

}

在这个示例中,首先生成一个包含10Hz和100Hz正弦波的测试信号。然后,使用bandPassFilter函数生成一个通带在20Hz到80Hz之间的带通滤波器。最后,使用filter函数对测试信号进行带通滤波,输出滤波后的信号。

12.自适应滤波

原理

自适应滤波是一种根据输入信号自动调整滤波器参数的滤波方法。该方法通过分析信号的特性,自动调整滤波器参数以达到最优的滤波效果。

常见的自适应滤波方法包括基于卡尔曼滤波、基于最小均方差(LMS)算法、基于最小二乘(RLS)算法等。

其中,LMS算法是一种简单而有效的自适应滤波算法,它根据当前误差的大小自适应地更新滤波器的系数,从而达到最小化误差的目的。LMS算法的实现过程如下:

初始化滤波器的系数,通常为0。将输入信号x[n]送入滤波器,并得到输出信号y[n]。计算当前的误差e[n] = d[n] - y[n],其中d[n]为期望输出。根据LMS算法的公式更新滤波器系数,即:w[i] = w[i] + mu * e[n] * x[n-i],其中mu为步长因子。重复2~4步直到收敛。

自适应滤波适用于信号在时间和频率上都随时间变化的情况,例如音频信号中的噪声、抖动等干扰。它能够自动地调整滤波器的参数以适应输入信号的变化,从而获得更好的滤波效果。

代码

下面是一个基于LMS算法的自适应滤波器的C语言实现示例,包括滤波器初始化、滤波器更新、滤波器输出三个部分。

C语言代码:

#include

#include

#define N 10  /* 滤波器长度 */

#define LAMBDA 0.1  /* 步长 */

#define DELTA 0.001  /* 初始误差 */

#define M 10  /* 信号长度 */

/* 自适应滤波器初始化 */

void initFilter(double *w) {

    int i;

    for (i = 0; i < N; i++) {

        w[i] = 0;

    }

}

/* 自适应滤波器更新 */

void updateFilter(double *w, double *x, double *d) {

    int i, j;

    double y, e;

    double u[N];  /* 输入向量 */

   

    /* 初始化输入向量 */

    for (i = 0; i < N; i++) {

        u[i] = 0;

        for (j = 0; j < N; j++) {

            if (i >= j) {

                u[i] += x[i - j] * w[j];

            }

        }

    }

    /* 计算输出、误差和权值更新 */

    for (i = 0; i < M; i++) {

        y = 0;

        for (j = 0; j < N; j++) {

            y += x[i - j] * w[j];

        }

        e = d[i] - y;

        for (j = 0; j < N; j++) {

            w[j] += LAMBDA * e * u[j];

        }

    }

}

/* 自适应滤波器输出 */

void filter(double *w, double *x, double *y) {

    int i, j;

    for (i = 0; i < M; i++) {

        y[i] = 0;

        for (j = 0; j < N; j++) {

            y[i] += x[i - j] * w[j];

        }

    }

}

int main() {

    int i;

    double w[N];  /* 滤波器权值 */

    double x[M];  /* 输入信号 */

    double d[M];  /* 期望信号 */

    double y[M];  /* 输出信号 */

    /* 初始化输入信号和期望信号 */

    for (i = 0; i < M; i++) {

        x[i] = sin(i);

        d[i] = sin(i + 1);

    }

    /* 自适应滤波器初始化 */

    initFilter(w);

    /* 自适应滤波器更新 */

    updateFilter(w, x, d);

    /* 自适应滤波器输出 */

    filter(w, x, y);

    /* 输出结果 */

    for (i = 0; i < M; i++) {

        printf("x[%d] = %f, d[%d] = %f, y[%d] = %f\n", i, x[i], i, d[i], i, y[i]);

    }

   

    return 0;

}

以上代码实现了基于LMS算法的自适应滤波器,并进行了一个简单的测试。代码中首先定义了滤波器的长度N、步长LAMBDA、初始误差DELTA和信号长度M等参数。然后定义了三个主要的函数:初始化滤波器权值的函数initFilter、更新滤波器权值的函数updateFilter和计算滤波器输出的函数filter。

在main函数中,先初始化输入信号x和期望信号d,然后调用initFilter函数初始化滤波器权值。接着,调用updateFilter函数更新滤波器权值。最后,调用filter函数计算滤波器的输出y。程序预测输出结果为一个长度为M的数组y,表示滤波器对输入信号x的滤波结果。

由于输入信号x和期望信号d是根据sin函数生成的,因此预测输出结果也将是一个sin函数的变化曲线。具体的输出结果将受到LAMBDA、DELTA、N和M等参数的影响。如果LAMBDA较小,则滤波器收敛速度较慢,但精度较高;如果LAMBDA较大,则滤波器收敛速度较快,但精度较低。DELTA越小,滤波器收敛速度越快。N越大,滤波器的滤波效果越好,但计算量也会增加。M越大,滤波器的滤波效果也会越好,但计算量同样也会增加。

下一章:高级滤波器

卡尔曼滤波器:卡尔曼滤波器是一种递归滤波算法,可以用于估计一个物理系统的状态。它结合了测量值和预测值,通过动态地调整预测值的权重,来提高状态估计的准确性。卡尔曼滤波器可以应用于多种不同的领域,如控制、导航、信号处理等。均值迁移滤波器:均值迁移滤波器是一种非参数滤波算法,通过不断调整窗口大小和中心位置来寻找数据的密度峰值,并对数据进行聚类。均值迁移滤波器可以应用于图像处理、目标跟踪等领域。小波变换滤波器:小波变换滤波器将信号分解成多个不同频率的子带,并对每个子带进行滤波处理。小波变换滤波器可以提供比传统滤波器更好的时频分辨率和去噪效果。它可以应用于语音信号处理、图像处理等领域。基于局部线性嵌入的滤波器:基于局部线性嵌入的滤波器利用局部线性嵌入方法对数据进行降维和压缩,然后对压缩后的数据进行滤波处理。它可以应用于高维数据的降维和去噪等领域。

总的来说,滤波算法有很多种,每种算法都有自己的特点和适用范围。选择合适的滤波算法需要根据具体应用场景和数据特征进行综合考虑。

□作者:队友调车我吹空调

关注我的csdn:Asakura Taka的博客_CSDN博客-领域博主

网址:https://blog.csdn.net/m0_62545037?spm=1010.2135.3001.5421

转载请标明来源

查看原文