完整的源代码、逐行分析及调用示例

源代码:4阶IIR滤波器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
typedef float flt32_t;

typedef struct IirFilter4thCoef_ {
flt32_t B[5]; // 前馈系数 (B0, B1, B2, B3, B4)
flt32_t A[5]; // 反馈系数 (A0, A1, A2, A3, A4)
} IirFilter4thCoef;

typedef struct IirFilter4th_ {
flt32_t x_delay[4]; // 延迟输入 (x[n-1], x[n-2], x[n-3], x[n-4])
flt32_t y_delay[4]; // 延迟输出 (y[n-1], y[n-2], y[n-3], y[n-4])
} IirFilter4th;

static inline flt32_t IirFilter4th_Proc(flt32_t input, const IirFilter4thCoef *coef, IirFilter4th *filter)
{
flt32_t output; // 输出
flt32_t bx = coef->B[0] * input; // 计算前馈部分
flt32_t ay = 0.f; // 反馈部分初始化为0
int16_t i;

// 计算前馈和反馈部分
for (i = 0; i < 4; i++)
{
bx += coef->B[i + 1] * filter->x_delay[i]; // 前馈项:过去输入的加权和
ay += coef->A[i + 1] * filter->y_delay[i]; // 反馈项:过去输出的加权和
}

output = (bx - ay) / coef->A[0]; // 输出结果为前馈部分减去反馈部分,再除以A[0]

// 更新延迟数组,将新输入和新输出插入
for (i = 3; i > 0; i--)
{
filter->x_delay[i] = filter->x_delay[i - 1]; // 延迟输入更新
filter->y_delay[i] = filter->y_delay[i - 1]; // 延迟输出更新
}

filter->x_delay[0] = input; // 当前输入保存到x_delay[0]
filter->y_delay[0] = output; // 当前输出保存到y_delay[0]

return output; // 返回滤波后的输出
}

代码逐行分析:

结构体定义

  1. IirFilter4thCoef 结构体定义:

    1
    2
    3
    4
    typedef struct IirFilter4thCoef_ {
    flt32_t B[5];
    flt32_t A[5];
    } IirFilter4thCoef;
    • B[5]A[5] 分别表示IIR滤波器的前馈(feedforward)和反馈(feedback)系数。滤波器的输出由这两个系数控制。
  2. IirFilter4th 结构体定义:

    1
    2
    3
    4
    typedef struct IirFilter4th_ {
    flt32_t x_delay[4]; // 前四个输入的延迟
    flt32_t y_delay[4]; // 前四个输出的延迟
    } IirFilter4th;
    • x_delay[4]y_delay[4] 存储最近4个输入和输出的延迟值,帮助计算当前输出。

函数 IirFilter4th_Proc 的实现:

1
static inline flt32_t IirFilter4th_Proc(flt32_t input, const IirFilter4thCoef *coef, IirFilter4th *filter)
  • 输入参数
    • input:当前输入的信号值。
    • coef:指向存储滤波器前馈和反馈系数的结构体的指针。
    • filter:指向滤波器的状态(延迟输入和输出)的指针。
  1. 初始化变量

    1
    2
    3
    flt32_t output;
    flt32_t bx = coef->B[0] * input; // 前馈计算从B[0] * input开始
    flt32_t ay = 0.f; // 反馈部分初始值
    • bx 是前馈部分的初始值,由当前输入乘以系数 B[0] 计算。
    • ay 是反馈部分,初始为0,用于存储反馈项的计算结果。
  2. 计算前馈和反馈部分

    1
    2
    3
    4
    5
    for (i = 0; i < 4; i++)
    {
    bx += coef->B[i + 1] * filter->x_delay[i]; // 前馈项
    ay += coef->A[i + 1] * filter->y_delay[i]; // 反馈项
    }
    • 该循环对先前的4个输入 (x_delay) 和输出 (y_delay) 进行处理:
      • bx 累加过去的输入值乘以前馈系数 B[i+1]
      • ay 累加过去的输出值乘以反馈系数 A[i+1]
  3. 计算输出

    1
    output = (bx - ay) / coef->A[0];  // 前馈 - 反馈 / A[0]
    • 输出值是前馈项减去反馈项,再除以 A[0],这符合IIR滤波器的标准公式。
  4. 更新延迟缓冲区

    1
    2
    3
    4
    5
    6
    7
    for (i = 3; i > 0; i--)
    {
    filter->x_delay[i] = filter->x_delay[i - 1]; // 更新x延迟
    filter->y_delay[i] = filter->y_delay[i - 1]; // 更新y延迟
    }
    filter->x_delay[0] = input; // 当前输入保存为最新延迟
    filter->y_delay[0] = output; // 当前输出保存为最新延迟
    • 延迟缓冲区的元素依次向后移动,以保持滤波器的状态。当前输入和输出被放置在缓冲区的最前面 (x_delay[0]y_delay[0])。
  5. 返回输出

    1
    return output;  // 返回当前滤波后的输出

函数调用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>

int main() {
// 定义滤波器系数
IirFilter4thCoef coef = {
.B = {0.1f, 0.15f, 0.15f, 0.1f, 0.05f}, // 前馈系数
.A = {1.0f, 0.2f, 0.3f, 0.4f, 0.1f} // 反馈系数
};

// 初始化滤波器状态(延迟输入和输出)
IirFilter4th filter = {
.x_delay = {0, 0, 0, 0}, // 初始输入延迟为0
.y_delay = {0, 0, 0, 0} // 初始输出延迟为0
};

// 输入信号序列
flt32_t input_signal[] = {1.0f, 0.5f, -0.5f, -1.0f, 0.0f};
int n = sizeof(input_signal) / sizeof(input_signal[0]);

// 滤波后的输出
for (int i = 0; i < n; i++) {
flt32_t output = IirFilter4th_Proc(input_signal[i], &coef, &filter);
printf("Input: %.2f, Output: %.2f\n", input_signal[i], output);
}

return 0;
}

运行示例输出:

1
2
3
4
5
Input:  1.00, Output:  0.10
Input: 0.50, Output: 0.18
Input: -0.50, Output: 0.11
Input: -1.00, Output: -0.12
Input: 0.00, Output: -0.22

总结:

  • 结构体 IirFilter4thCoef:保存了4阶IIR滤波器的前馈系数(B[5])和反馈系数(A[5])。
  • 结构体 IirFilter4th:保存了滤波器的状态,即最近4个输入(x_delay[4])和输出(y_delay[4])。
  • IirFilter4th_Proc 函数:处理每一个输入样本,通过递归的方式结合过去的输入和输出计算当前的输出,并更新滤波器的状态。

通过该实现,您可以对输入信号进行4阶IIR滤波。