目录
1.算术平均滤波
原理
算术平均滤波是一种最简单常用的数字滤波算法之一,也是一种基于时间域的滤波方法。其原理是将连续采集到的一组数据进行加和,并求出其平均值,以此作为滤波后的输出值。这种方法能够有效平滑信号,去除噪声干扰,同时保留信号的趋势和主要特征。
算术平均滤波的基本原理是取一段时间内的信号值的平均值作为输出。这段时间可以是固定的,也可以是动态调整的,取决于具体的实现。
-
初始化: 设置一个窗口大小(表示取平均的时间范围)和一个缓存区,用于存储窗口内的信号值。
-
输入信号: 在每个时刻,输入一个新的信号值。
-
更新缓存区: 将新的信号值加入缓存区,并去除窗口之外的最早的信号值,以保持窗口大小不变。
-
计算平均值: 对缓存区内的所有信号值取平均值。
-
输出: 将平均值作为输出信号。
算术平均滤波对于平稳的信号非常有效,因为它能够消除瞬时噪声。然而,它对于快速变化的信号响应较慢,因为窗口内的信号值需要时间来适应变化。
代码
#include <stdio.h>
#define WINDOW_SIZE 5
// 定义算术平均滤波器结构体
typedef struct {
int window[WINDOW_SIZE];
int index;
} AverageFilter;
// 初始化滤波器
void initializeFilter(AverageFilter* filter) {
for (int i = 0; i < WINDOW_SIZE; ++i) {
filter->window[i] = 0;
}
filter->index = 0;
}
// 算术平均滤波函数
int filterValue(AverageFilter* filter, int input) {
// 更新缓存区
filter->window[filter->index] = input;
filter->index = (filter->index + 1) % WINDOW_SIZE;
// 计算平均值
int sum = 0;
for (int i = 0; i < WINDOW_SIZE; ++i) {
sum += filter->window[i];
}
int average = sum / WINDOW_SIZE;
return average;
}
int main() {
// 初始化滤波器
AverageFilter myFilter;
initializeFilter(&myFilter);
// 使用示例
int inputValues[] = {10, 15, 20, 18, 22, 25, 17};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
int filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%d\t\t%d\n", inputValues[i], filteredValue);
}
return 0;
}
AverageFilter
结构体用于存储滤波器的状态信息,包括一个窗口大小为 WINDOW_SIZE
的缓存区和当前索引。 initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了算术平均滤波的操作。在 main
函数中,我们创建了一个 AverageFilter
实例,并对一系列输入值进行滤波处理,输出平均值。
2.一阶滞后滤波
原理
一阶滞后滤波法是一种常见的滤波方法,也被称为指数加权平均滤波。它基于一个简单的思想,即当前的输出值是前一次输出值和当前输入值的加权平均值。这种加权平均值的计算方法使得前一次的输出值在当前输出值中占有一定的比重,从而可以平滑信号,并减小由于突然变化引起的干扰。
一阶滞后滤波的基本原理是通过引入一个时间常数(time constant)来调节滞后程度。时间常数决定了滤波器对信号变化的响应速度。较大的时间常数会导致较慢的响应,更强的平滑效果,但可能较慢地跟踪信号的快速变化;较小的时间常数则会导致较快的响应,但可能对噪声更敏感。
一阶滞后滤波的差分方程可以表示为:
其中:
是当前时刻的输出。
是上一时刻的输出。
是当前时刻的输入。
是介于 0 和 1 之间的常数,表示时间常数。
在这个方程中, 越接近 1,滤波器的响应就越慢,平滑效果越强。
代码
#include <stdio.h>
// 定义一阶滞后滤波器结构体
typedef struct {
float alpha; // 时间常数
float previous_output;
} FirstOrderLagFilter;
// 初始化滤波器
void initializeFilter(FirstOrderLagFilter* filter, float alpha) {
filter->alpha = alpha;
filter->previous_output = 0.0;
}
// 一阶滞后滤波函数
float filterValue(FirstOrderLagFilter* filter, float input) {
// 计算输出
float output = (1.0 - filter->alpha) * filter->previous_output + filter->alpha * input;
// 更新上一次的输出
filter->previous_output = output;
return output;
}
int main() {
// 初始化滤波器,设置时间常数为0.2
FirstOrderLagFilter myFilter;
initializeFilter(&myFilter, 0.2);
// 使用示例
float inputValues[] = {10.0, 15.0, 20.0, 18.0, 22.0, 25.0, 17.0};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
float filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%.2f\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}
FirstOrderLagFilter
结构体用于存储滤波器的状态信息,包括时间常数和上一次的输出。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了一阶滞后滤波的操作。在 main
函数中,我们创建了一个 FirstOrderLagFilter
实例,并对一系列输入值进行滤波处理,输出滤波后的值。
3.限幅消抖滤波
原理
限幅消抖滤波法是一种简单有效的数字滤波算法,常用于对采集到的离散信号进行去抖动处理。它可以去除信号中的瞬时噪声和突发干扰,同时保留信号的主要特征。
限幅消抖滤波法的原理是通过设置一个合适的阈值,将信号限制在一个固定的范围内,并消除信号中的抖动。当信号的变化速度超过阈值时,限制信号的变化幅度,以消除抖动;当信号变化速度较缓时,允许信号在一定范围内波动,以保留信号的主要特征。在实际应用中,通常将限幅消抖滤波法与其他滤波算法结合使用,以进一步提高滤波效果。
-
限幅(Clipping): 首先,将输入信号限制在一个预定的范围内。这个范围由上下限值确定。如果输入信号超出这个范围,它将被截断或限制在范围的边界上。
-
消抖(Debouncing): 消抖是指去除输入信号中的瞬时干扰或噪声,以获得更加平滑的输出。这可以通过在一定时间内对输入信号进行平均、滤波或延时来实现。
限幅消抖滤波的应用场景主要涉及那些由于环境原因或传感器特性而引入干扰的系统。例如,当使用传感器测量某个物理量时,由于传感器的特性或环境噪声,可能会产生一些突发的异常值。通过限制幅度和消除瞬时干扰,可以得到更加稳定和可靠的测量结果。在一些要求实时性较高的应用中,可能会选择简单的限幅操作。在对信号平滑性要求较高的场合,可能需要采用更复杂的滤波算法。
代码
#include <stdio.h>
// 定义限幅消抖滤波器结构体
typedef struct {
int min_limit;
int max_limit;
int previous_value;
int smoothing_factor;
} Filter;
// 初始化滤波器
void initializeFilter(Filter* filter, int min_limit, int max_limit, int smoothing_factor) {
filter->min_limit = min_limit;
filter->max_limit = max_limit;
filter->previous_value = 0; // 初始值为0
filter->smoothing_factor = smoothing_factor;
}
// 限幅消抖滤波函数
int filterValue(Filter* filter, int input) {
// 限幅
if (input < filter->min_limit) {
input = filter->min_limit;
} else if (input > filter->max_limit) {
input = filter->max_limit;
}
// 消抖(滑动平均)
int output = (filter->previous_value * (filter->smoothing_factor - 1) + input) / filter->smoothing_factor;
// 更新上一次的值
filter->previous_value = output;
return output;
}
int main() {
// 初始化滤波器,设置限幅范围为[0, 100],消抖因子为3
Filter myFilter;
initializeFilter(&myFilter, 0, 100, 3);
// 使用示例
int inputValues[] = {50, 120, 80, 90, 110, 30, 70};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
int filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%d\t\t%d\n", inputValues[i], filteredValue);
}
return 0;
}
Filter
结构体用于存储滤波器的状态信息,包括限幅范围、上一次的值以及消抖因子。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了限幅和滑动平均消抖的操作。在 main
函数中,我们创建了一个 Filter
实例,并对一系列输入值进行滤波处理,输出限幅和消抖后的值。
4.递推平均滤波
原理
递推平均滤波法,又称为滑动平均滤波法,是一种对于输入信号进行平滑处理的算法。该算法采用一定的方式对一定数量的输入信号进行加权平均,得到一个平滑的输出信号。具体地,递推平均滤波法使用一个固定长度的窗口,每当有新的输入信号到来时,就将窗口内的旧的信号淘汰掉,并将新的信号加入到窗口中,然后重新计算窗口内所有信号的平均值作为当前的输出信号。因此,随着新的信号不断到来,窗口内的信号会不断滑动,而输出信号也会不断变化,从而实现对输入信号的平滑处理。
递推平均滤波法的优点是简单、实时性好,对于周期性的噪声有一定的抑制效果。其缺点是在处理突变的输入信号时,输出信号会有一定的延迟,且在窗口大小不够大的情况下,噪声的抑制效果会比较有限。
下面是递推平均滤波法的算法步骤:
- 定义一个固定长度为
的窗口,并初始化窗口内的所有数据为 0。
- 当有新的输入信号
到来时,将窗口内的第一个信号
移除,并将新的信号
加入到窗口中。
- 计算窗口内所有信号的平均值,作为当前的输出信号
。
- 返回输出信号
,并等待下一次输入信号到来。
代码
#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;
}
其中,N 为窗口大小,x 表示输入信号,y 表示输出信号,buffer 为窗口缓存,sum 为窗口内数据的累加和。
在这个函数中,我们使用了一个静态的窗口缓存 buffer 来存储窗口内的数据,使用 sum 来记录窗口内数据的累加和,使用 ptr 来记录当前窗口内最后一个数据的位置。当有新的输入信号 x 到来时,我们将窗口内第一个数据 buffer[ptr-N] 移除,并将新的信号 x 加入到窗口中。然后,我们重新计算窗口内所有信号的平均值作为当前的输出信号,并将作为当前的输出信号,返回输出信号,并等待下一次输入信号到来。
5.加权递推平均滤波
原理
加权递推平均滤波是一种滤波技术,它对信号的当前值和过去的滤波结果进行加权组合,以获得平滑的输出。与一阶滞后滤波不同,加权递推平均滤波使用多个权重来对不同时刻的输入信号进行加权,以更灵活地调整对历史数据的依赖程度。
其中:
是当前时刻的输出。
是过去的输入信号值,
表示过去的时间步。
是权重系数,表示对应时刻的权重。
权重系数的选择是加权递推平均滤波的关键,它决定了滤波器对历史数据的关注程度。通常情况下,权重系数越大,对应时刻的输入信号在输出中的影响就越大。这样设计的目的是在保持对当前值敏感的同时,平滑掉噪声或瞬时变化。
代码
#include <stdio.h>
#define NUM_WEIGHTS 3
// 定义加权递推平均滤波器结构体
typedef struct {
float weights[NUM_WEIGHTS];
float buffer[NUM_WEIGHTS];
int index;
} WeightedRecursiveAverageFilter;
// 初始化滤波器
void initializeFilter(WeightedRecursiveAverageFilter* filter, float* weights) {
for (int i = 0; i < NUM_WEIGHTS; ++i) {
filter->weights[i] = weights[i];
filter->buffer[i] = 0.0;
}
filter->index = 0;
}
// 加权递推平均滤波函数
float filterValue(WeightedRecursiveAverageFilter* filter, float input) {
// 更新缓存区
filter->buffer[filter->index] = input;
filter->index = (filter->index + 1) % NUM_WEIGHTS;
// 计算加权平均值
float output = 0.0;
for (int i = 0; i < NUM_WEIGHTS; ++i) {
output += filter->weights[i] * filter->buffer[(filter->index - i + NUM_WEIGHTS) % NUM_WEIGHTS];
}
return output;
}
int main() {
// 初始化滤波器,设置权重系数
float weights[] = {0.2, 0.5, 0.3};
WeightedRecursiveAverageFilter myFilter;
initializeFilter(&myFilter, weights);
// 使用示例
float inputValues[] = {10.0, 15.0, 20.0, 18.0, 22.0, 25.0, 17.0};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
float filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%.2f\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}
WeightedRecursiveAverageFilter
结构体用于存储滤波器的状态信息,包括权重系数和缓存区。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了加权递推平均滤波的操作。在 main
函数中,我们创建了一个 WeightedRecursiveAverageFilter
实例,并对一系列输入值进行滤波处理,输出滤波后的值。
6.中值滤波
原理
中值滤波是一种非线性滤波方法,常用于去除信号中的脉冲噪声或椒盐噪声。它的原理是将一组数据排序,然后选择中间位置的值作为滤波结果。中值滤波对于去除离群值(异常值)非常有效,因为它不受异常值的影响。
-
选择窗口大小: 窗口大小决定了用于计算中值的数据点数量。通常,窗口大小是一个奇数,以确保存在中间位置的值。
-
将窗口内的数据排序: 对窗口内的数据进行排序,确定中间位置的值。
-
选择中值: 选择排序后的数据集的中间位置的值作为输出。
中值滤波的优势在于它能够有效地保留信号的边缘信息,而不像线性滤波那样引入过多的平滑。因此,中值滤波在一些对信号细节要求较高的应用中比较有用。需要注意的是,中值滤波可能会导致信号的某些特征被模糊化,因此在应用中需要谨慎选择邻域大小和形状,以及滤波器的使用场景。
代码
#include <stdio.h>
#include <stdlib.h>
#define WINDOW_SIZE 3
// 定义中值滤波器结构体
typedef struct {
int window[WINDOW_SIZE];
} MedianFilter;
// 初始化滤波器
void initializeFilter(MedianFilter* filter) {
// 初始化窗口
for (int i = 0; i < WINDOW_SIZE; ++i) {
filter->window[i] = 0;
}
}
// 中值滤波函数
int filterValue(MedianFilter* filter, int input) {
// 将新的值插入窗口
for (int i = WINDOW_SIZE - 1; i > 0; --i) {
filter->window[i] = filter->window[i - 1];
}
filter->window[0] = input;
// 对窗口内的数据进行排序
for (int i = 0; i < WINDOW_SIZE - 1; ++i) {
for (int j = i + 1; j < WINDOW_SIZE; ++j) {
if (filter->window[j] < filter->window[i]) {
// 交换值
int temp = filter->window[i];
filter->window[i] = filter->window[j];
filter->window[j] = temp;
}
}
}
// 选择中值
int median = filter->window[WINDOW_SIZE / 2];
return median;
}
int main() {
// 初始化滤波器
MedianFilter myFilter;
initializeFilter(&myFilter);
// 使用示例
int inputValues[] = {10, 15, 20, 18, 22, 25, 17};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
int filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%d\t\t%d\n", inputValues[i], filteredValue);
}
return 0;
}
MedianFilter
结构体用于存储滤波器的状态信息,包括一个窗口。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了中值滤波的操作。在 main
函数中,我们创建了一个 MedianFilter
实例,并对一系列输入值进行滤波处理,输出中值。
7.中位值平均滤波法
原理
中位值平均滤波法(Median Filtering with Averaging)是一种结合了中值滤波和平均滤波的方法。在这种滤波法中,首先通过中值滤波获得当前时刻的输出,然后将该输出与一定时期内的平均值进行加权平均。这种方法的目的是综合利用中值滤波和平均滤波的优势,对信号进行平滑处理,并能够有效地去除脉冲噪声或其他突发性噪声。
中位值平均滤波法的基本步骤如下:
-
中值滤波: 使用中值滤波器,通过排序窗口内的数据并选择中间值,得到一个初步的滤波结果。
-
平均滤波: 将中值滤波得到的结果与一定时期内的平均值进行加权平均。通常,这里的平均值是使用递推平均滤波法得到的。
-
输出: 输出平均滤波的结果作为最终的滤波输出。
这种滤波法的优势在于中值滤波能够有效去除离群值和脉冲噪声,而平均滤波则能够对信号进行较好的平滑。通过结合这两种方法,中位值平均滤波法在一些特定噪声环境下表现得比单一滤波方法更为鲁棒。
代码
#include <stdio.h>
#define WINDOW_SIZE 5
// 定义中位值平均滤波器结构体
typedef struct {
int window[WINDOW_SIZE];
float alpha; // 平均滤波的权重系数
} MedianAverageFilter;
// 初始化滤波器
void initializeFilter(MedianAverageFilter* filter, float alpha) {
for (int i = 0; i < WINDOW_SIZE; ++i) {
filter->window[i] = 0;
}
filter->alpha = alpha;
}
// 中位值平均滤波函数
float filterValue(MedianAverageFilter* filter, int input) {
// 更新窗口
for (int i = WINDOW_SIZE - 1; i > 0; --i) {
filter->window[i] = filter->window[i - 1];
}
filter->window[0] = input;
// 中值滤波
int sortedValues[WINDOW_SIZE];
for (int i = 0; i < WINDOW_SIZE; ++i) {
sortedValues[i] = filter->window[i];
}
for (int i = 0; i < WINDOW_SIZE - 1; ++i) {
for (int j = i + 1; j < WINDOW_SIZE; ++j) {
if (sortedValues[j] < sortedValues[i]) {
// 交换值
int temp = sortedValues[i];
sortedValues[i] = sortedValues[j];
sortedValues[j] = temp;
}
}
}
int median = sortedValues[WINDOW_SIZE / 2];
// 平均滤波
float output = (1.0 - filter->alpha) * median + filter->alpha * input;
return output;
}
int main() {
// 初始化滤波器,设置平均滤波的权重系数
float alpha = 0.2;
MedianAverageFilter myFilter;
initializeFilter(&myFilter, alpha);
// 使用示例
int inputValues[] = {10, 15, 20, 18, 22, 25, 17};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
float filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%d\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}
MedianAverageFilter
结构体用于存储滤波器的状态信息,包括窗口和平均滤波的权重系数。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了中位值平均滤波的操作。在 main
函数中,我们创建了一个 MedianAverageFilter
实例,并对一系列输入值进行滤波处理,输出滤波后的值。
8.一阶低通滤波
原理
低通滤波(Low Pass Filter)用于从一个信号中去除高于某个频率的成分。它的基本原理是,信号中高于某个频率的成分在信号传输或接收过程中会发生衰减,而低于该频率的成分则不受影响。因此,通过将信号通过一个低通滤波器,可以去除高频噪声,保留信号中的低频成分。
一阶低通滤波器是低通滤波的一阶离散形式,用于滤除输入信号中的高频分量,只保留低频分量。它通过减弱高频部分的幅度,从而实现对信号的平滑处理。一阶低通滤波器的基本原理涉及限制信号的变化速率,对快速变化的信号进行衰减,而对缓慢变化的信号保留。
一阶低通滤波的形式与一阶滞后滤波完全相同。倒不如说一阶滞后滤波其实就是一阶低通滤波,只不过当该滤波器用于不同的作用时,我们将其冠以了不同的称呼。
其中:
是当前时刻的输出。
是上一时刻的输出。
是当前时刻的输入。
是介于 0 和 1 之间的常数,表示时间常数。
在这个方程中, 越小,时间常数越大,低通滤波器的截止频率就越低,对高频部分的抑制效果就越强。
一阶低通滤波器常用于需要平滑信号或去除高频噪声的应用场景。它们在信号处理、通信系统、控制系统等领域都有广泛的应用。
代码
#include <stdio.h>
// 定义一阶低通滤波器结构体
typedef struct {
float alpha; // 时间常数
float previous_output; // 上一时刻的输出
} LowPassFilter;
// 初始化滤波器
void initializeFilter(LowPassFilter* filter, float alpha) {
filter->alpha = alpha;
filter->previous_output = 0.0;
}
// 一阶低通滤波函数
float filterValue(LowPassFilter* filter, float input) {
// 计算输出
float output = (1.0 - filter->alpha) * filter->previous_output + filter->alpha * input;
// 更新上一次的输出
filter->previous_output = output;
return output;
}
int main() {
// 初始化滤波器,设置时间常数为0.2
float alpha = 0.2;
LowPassFilter myFilter;
initializeFilter(&myFilter, alpha);
// 使用示例
float inputValues[] = {10.0, 15.0, 20.0, 18.0, 22.0, 25.0, 17.0};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
float filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%.2f\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}
LowPassFilter
结构体用于存储滤波器的状态信息,包括时间常数和上一次的输出。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了一阶低通滤波的操作。在 main
函数中,我们创建了一个 LowPassFilter
实例,并对一系列输入值进行滤波处理,输出滤波后的值。
9.二阶低通滤波
原理
二阶低通滤波器是低通滤波器的二阶差分形式,用于滤除输入信号中的高频分量,同时保留低频分量。相比于一阶低通滤波器,二阶低通滤波器在频域上更为复杂,具有更陡的滤波特性。它可以更有效地抑制高频噪声,同时允许低频信号通过。
一个常见的二阶低通滤波器可以通过差分方程表示为:
其中:
是当前时刻的输出。
和
是上两个时刻的输出。
是当前时刻的输入。
和
是介于 0 和 1 之间的常数,分别表示两个不同的时间常数,决定了滤波器的特性。
在这个方程中, 和
的选择影响了滤波器的频率响应和阶数。较小的时间常数表示较大的截止频率,而较大的时间常数表示较小的截止频率。这样,可以根据具体需求调整时间常数来达到期望的滤波效果。
二阶低通滤波器通常应用于需要更复杂频率响应和更好滤波性能的情况,如音频处理、图像处理和控制系统等领域。
代码
#include <stdio.h>
// 定义二阶低通滤波器结构体
typedef struct {
float alpha; // 第一个时间常数
float beta; // 第二个时间常数
float previous_output[2]; // 上两个时刻的输出
} SecondOrderLowPassFilter;
// 初始化滤波器
void initializeFilter(SecondOrderLowPassFilter* filter, float alpha, float beta) {
filter->alpha = alpha;
filter->beta = beta;
filter->previous_output[0] = 0.0;
filter->previous_output[1] = 0.0;
}
// 二阶低通滤波函数
float filterValue(SecondOrderLowPassFilter* filter, float input) {
// 计算输出
float output = (1.0 - filter->alpha - filter->beta) * filter->previous_output[1] +
2.0 * filter->alpha * filter->previous_output[0] +
filter->beta * input;
// 更新上两次的输出
filter->previous_output[1] = filter->previous_output[0];
filter->previous_output[0] = output;
return output;
}
int main() {
// 初始化滤波器,设置两个时间常数
float alpha = 0.1;
float beta = 0.1;
SecondOrderLowPassFilter myFilter;
initializeFilter(&myFilter, alpha, beta);
// 使用示例
float inputValues[] = {10.0, 15.0, 20.0, 18.0, 22.0, 25.0, 17.0};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
float filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%.2f\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}
SecondOrderLowPassFilter
结构体用于存储滤波器的状态信息,包括两个时间常数和上两次的输出。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了二阶低通滤波的操作。在 main
函数中,我们创建了一个 SecondOrderLowPassFilter
实例,并对一系列输入值进行滤波处理,输出滤波后的值。
10.一阶高通滤波
原理
高通滤波(High Pass Filter)可以滤除信号中的低频部分,保留高频部分。高通滤波器的应用非常广泛,例如在音频处理中可以用来去除低频噪声、在图像处理中可以用来增强图像的边缘等。
高通滤波算法的基本思想是:将信号分解成高频和低频两部分,去掉低频部分,只保留高频部分。高通滤波的实现可以通过频域方法和时域方法两种方式实现。
频域方法是将信号转换到频域进行处理,常用的有傅里叶变换和小波变换等。通过滤波器在频域中滤除低频成分,然后再将信号转换回时域。
时域方法则是通过差分等方式,直接在时域中滤除低频部分。
一阶高通滤波器是高通滤波的一阶差分形式,用于滤除输入信号中的低频分量,同时保留高频分量。高通滤波器的作用是弱化或消除信号中的低频成分,从而突出高频变化或忽略缓慢变化的部分。一阶高通滤波器的设计原理涉及对低频分量进行衰减,保留高频部分。
一阶高通滤波器的差分方程一般表示为:
其中:
是当前时刻的输出。
是上一时刻的输出。
是当前时刻的输入。
是介于 0 和 1 之间的常数,表示时间常数,决定了滤波器的截止频率。
在这个方程中, 越小,时间常数越大,高通滤波器的截止频率就越低,对低频部分的抑制效果就越弱。
一阶高通滤波器通常应用于需要突出信号中快速变化或高频成分的应用场景。在图像处理、音频处理、传感器信号处理等领域,高通滤波器被广泛用于去除低频噪声或趋势成分。
代码
#include <stdio.h>
// 定义一阶高通滤波器结构体
typedef struct {
float alpha; // 时间常数
float previous_output; // 上一时刻的输出
} HighPassFilter;
// 初始化滤波器
void initializeFilter(HighPassFilter* filter, float alpha) {
filter->alpha = alpha;
filter->previous_output = 0.0;
}
// 一阶高通滤波函数
float filterValue(HighPassFilter* filter, float input) {
// 计算输出
float output = filter->alpha * (input - filter->previous_output) + filter->previous_output;
// 更新上一次的输出
filter->previous_output = output;
return output;
}
int main() {
// 初始化滤波器,设置时间常数为0.1
float alpha = 0.1;
HighPassFilter myFilter;
initializeFilter(&myFilter, alpha);
// 使用示例
float inputValues[] = {10.0, 15.0, 20.0, 18.0, 22.0, 25.0, 17.0};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
float filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%.2f\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}
HighPassFilter
结构体用于存储滤波器的状态信息,包括时间常数和上一次的输出。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了一阶高通滤波的操作。在 main
函数中,我们创建了一个 HighPassFilter
实例,并对一系列输入值进行滤波处理,输出滤波后的值。
11.二阶高通滤波
原理
二阶高通滤波器是高通滤波的二阶差分形式,用于滤除输入信号中的低频分量,同时保留高频分量。相较于一阶高通滤波器,二阶高通滤波器在频域上更为复杂,具有更陡的滤波特性。它可以更有效地抑制低频噪声,同时允许高频信号通过。
一个常见的二阶高通滤波器可以通过差分方程表示为:
其中:
是当前时刻的输出。
和
是上两个时刻的输出。
和
是上两个时刻的输入。
和
是介于 0 和 1 之间的常数,分别表示两个不同的时间常数,决定了滤波器的特性。
在这个方程中, 和
的选择影响了滤波器的频率响应和阶数。较小的时间常数表示较大的截止频率,而较大的时间常数表示较小的截止频率。这样,可以根据具体需求调整时间常数来达到期望的滤波效果。
二阶高通滤波器通常应用于需要更复杂频率响应和更好滤波性能的情况,如音频处理、图像处理和控制系统等领域。
代码
#include <stdio.h>
// 定义二阶高通滤波器结构体
typedef struct {
float alpha; // 第一个时间常数
float beta; // 第二个时间常数
float previous_output[2]; // 上两个时刻的输出
float previous_input[2]; // 上两个时刻的输入
} SecondOrderHighPassFilter;
// 初始化滤波器
void initializeFilter(SecondOrderHighPassFilter* filter, float alpha, float beta) {
filter->alpha = alpha;
filter->beta = beta;
filter->previous_output[0] = 0.0;
filter->previous_output[1] = 0.0;
filter->previous_input[0] = 0.0;
filter->previous_input[1] = 0.0;
}
// 二阶高通滤波函数
float filterValue(SecondOrderHighPassFilter* filter, float input) {
// 计算输出
float output = filter->alpha * (filter->previous_output[1] - filter->previous_input[1]) +
filter->beta * (input - 2.0 * filter->previous_input[1] + filter->previous_input[0]) +
filter->alpha * filter->previous_output[0];
// 更新上两次的输出和输入
filter->previous_output[1] = filter->previous_output[0];
filter->previous_output[0] = output;
filter->previous_input[1] = filter->previous_input[0];
filter->previous_input[0] = input;
return output;
}
int main() {
// 初始化滤波器,设置两个时间常数
float alpha = 0.1;
float beta = 0.1;
SecondOrderHighPassFilter myFilter;
initializeFilter(&myFilter, alpha, beta);
// 使用示例
float inputValues[] = {10.0, 15.0, 20.0, 18.0, 22.0, 25.0, 17.0};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
float filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%.2f\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}
SecondOrderHighPassFilter
结构体用于存储滤波器的状态信息,包括两个时间常数和上两次的输出和输入。initializeFilter
函数用于初始化滤波器,而 filterValue
函数实现了二阶高通滤波的操作。在 main
函数中,我们创建了一个 SecondOrderHighPassFilter
实例,并对一系列输入值进行滤波处理,输出滤波后的值。
12.带通有限脉冲响应滤波器(BPF)
原理
带通有限脉冲响应滤波器(Bandpass Finite Impulse Response Filter,BPF)是一种特殊类型的滤波器,其频率响应在频率域上对特定频率范围进行通带(通过)操作,而在其他频率范围上进行阻带(衰减)操作。与其他类型的滤波器相比,有限脉冲响应(FIR)滤波器的特点是其脉冲响应是有限长度的。
带通有限脉冲响应滤波器的设计通常涉及确定以下关键参数:
-
中心频率(
): 定义了通带的中心频率,即允许通过的频率范围的中点。
-
带宽(B): 定义了通带的宽度,即允许通过的频率范围的宽度。带宽通常表示为频率范围内通过的频率之间的差异。
-
通带波纹(Ripple): 描述了通带内允许的最大振幅变化。
-
阻带衰减(Stopband Attenuation): 描述了阻带内信号被滤波器抑制的程度。
带通有限脉冲响应滤波器的传递函数可以表示为
其中:
是频率响应。
是频率。
是滤波器的冲激响应系数。
是冲激响应的长度。
设计带通有限脉冲响应滤波器的方法包括窗函数法、频率采样法、最小均方误差法等。窗函数法是常用的一种设计方法,它通过在频域上使用窗函数来截断冲激响应。
带通有限脉冲响应滤波器在信号处理领域中广泛应用,特别是在通信系统、音频处理和生物医学信号处理等领域。带通滤波器可用于从混合信号中选择特定频率范围的组件,或者用于调整信号的频率特性。
代码
#include <stdio.h>
#include <math.h>
#define N 64 // 滤波器的冲激响应长度
// 定义带通有限脉冲响应滤波器结构体
typedef struct {
double h[N]; // 冲激响应系数
double buffer[N]; // 缓冲区
} BandpassFilter;
// 初始化滤波器
void initializeFilter(BandpassFilter* filter) {
// 假设中心频率为0.1,带宽为0.02,采样率为1
double fc = 0.1;
double B = 0.02;
double fs = 1.0;
// 计算冲激响应系数
for (int n = 0; n < N; ++n) {
double t = n - (N - 1) / 2.0;
if (t == 0) {
filter->h[n] = 2 * fc / fs;
} else {
filter->h[n] = (sin(2 * M_PI * fc * t / fs) / (M_PI * t)) * sin(2 * M_PI * B * t / fs);
}
}
// 初始化缓冲区
for (int i = 0; i < N; ++i) {
filter->buffer[i] = 0.0;
}
}
// 带通有限脉冲响应滤波函数
double filterValue(BandpassFilter* filter, double input) {
// 更新缓冲区
for (int i = N - 1; i > 0; --i) {
filter->buffer[i] = filter->buffer[i - 1];
}
filter->buffer[0] = input;
// 计算输出
double output = 0.0;
for (int i = 0; i < N; ++i) {
output += filter->h[i] * filter->buffer[i];
}
return output;
}
int main() {
// 初始化带通有限脉冲响应滤波器
BandpassFilter myFilter;
initializeFilter(&myFilter);
// 使用示例
double inputValues[] = {0.5, 0.2, -0.3, 0.8, -0.6, 0.4, -0.1};
int numValues = sizeof(inputValues) / sizeof(inputValues[0]);
printf("Input Values:\tFiltered Values:\n");
for (int i = 0; i < numValues; ++i) {
double filteredValue = filterValue(&myFilter, inputValues[i]);
printf("%.2f\t\t%.2f\n", inputValues[i], filteredValue);
}
return 0;
}