一、前言
IIR滤波器,递归滤波器,顾名思义,IIR滤波器采用递归型结构,结构上带有反馈回路。IIR数字滤波器相较于FIR数字滤波器具备幅频特性精度高的特点。
二、移植官方库
首先我们先将C2000 wave中我们所需要的函数库给导入到我们的新建工程中(可见于我实现FIR滤波文章中导入函数库的操作)。
工程中可见有以下文件。(仅进行滤波可删除FFT有关文件)
同时记得添加头文件路径
至此,对于我们进行滤波所需的函数库已经移植完毕。
三、借助MATLAB生成测试信号
使用MATLAB生成输入测试信号(相关程序可见于我另两篇文章)
%这里仅给出设定信号相关参数
fs=1e5; %设采样率为100K
f = [1e3,5e3,1e4]; %频率矩阵(1*N)测试信号频率为1K,5K,10K
phase = [0,0,0]; %初相位均为0
amp = [0.3,1.0,0.5];%幅度
N=512; %采样点数
生成信号的时域图与频域图如下:
将刚刚MATLAB生成的record.txt复制到input.c(没有就新建一个)中。
这里笔者给出自己生成好的输入信号
//#############################################################################
//! \file input.c
//! \brief Input Vector (1024)
//! \author Vishal Coelho
//! \date 16-Sep-2016
//!
//
// Group: C2000
// Target Family: $DEVICE$
//
//#############################################################################
//
//
// $Copyright: Copyright (C) 2022 Texas Instruments Incorporated -
// http://www.ti.com/ ALL RIGHTS RESERVED $
//#############################################################################
float test_input[512] = {
0.000000,0.621747,1.100913,1.340760,
1.319556,1.092705,0.767601,0.461223,
0.256783,0.175872,0.176336,0.176103,
0.093107,-0.114798,-0.426010,-0.757295,
-0.991651,-1.021653,-0.791865,-0.323977,
0.285317,0.893485,1.358000,1.582180,
1.544357,1.300000,0.956572,0.631123,
0.406943,0.305699,0.285317,0.263809,
0.159191,-0.070597,-0.403866,-0.757295,
-1.013795,-1.065855,-0.857949,-0.411682,
0.176336,0.763658,1.207840,1.412279,
1.355387,1.092705,0.731771,0.389703,
0.149857,0.033962,0.000000,-0.033962,
-0.149857,-0.389703,-0.731771,-1.092705,
-1.355387,-1.412279,-1.207840,-0.763658,
-0.176336,0.411682,0.857949,1.065855,
1.013795,0.757295,0.403866,0.070597,
-0.159191,-0.263809,-0.285317,-0.305699,
-0.406943,-0.631123,-0.956572,-1.300000,
-1.544357,-1.582180,-1.358000,-0.893485,
-0.285317,0.323977,0.791865,1.021653,
0.991651,0.757295,0.426010,0.114798,
-0.093107,-0.176103,-0.176336,-0.175872,
-0.256783,-0.461223,-0.767601,-1.092705,
-1.319556,-1.340760,-1.100913,-0.621747,
-0.000000,0.621747,1.100913,1.340760,
1.319556,1.092705,0.767601,0.461223,
0.256783,0.175872,0.176336,0.176103,
0.093107,-0.114798,-0.426010,-0.757295,
-0.991651,-1.021653,-0.791865,-0.323977,
0.285317,0.893485,1.358000,1.582180,
1.544357,1.300000,0.956572,0.631123,
0.406943,0.305699,0.285317,0.263809,
0.159191,-0.070597,-0.403866,-0.757295,
-1.013795,-1.065855,-0.857949,-0.411682,
0.176336,0.763658,1.207840,1.412279,
1.355387,1.092705,0.731771,0.389703,
0.149857,0.033962,0.000000,-0.033962,
-0.149857,-0.389703,-0.731771,-1.092705,
-1.355387,-1.412279,-1.207840,-0.763658,
-0.176336,0.411682,0.857949,1.065855,
1.013795,0.757295,0.403866,0.070597,
-0.159191,-0.263809,-0.285317,-0.305699,
-0.406943,-0.631123,-0.956572,-1.300000,
-1.544357,-1.582180,-1.358000,-0.893485,
-0.285317,0.323977,0.791865,1.021653,
0.991651,0.757295,0.426010,0.114798,
-0.093107,-0.176103,-0.176336,-0.175872,
-0.256783,-0.461223,-0.767601,-1.092705,
-1.319556,-1.340760,-1.100913,-0.621747,
-0.000000,0.621747,1.100913,1.340760,
1.319556,1.092705,0.767601,0.461223,
0.256783,0.175872,0.176336,0.176103,
0.093107,-0.114798,-0.426010,-0.757295,
-0.991651,-1.021653,-0.791865,-0.323977,
0.285317,0.893485,1.358000,1.582180,
1.544357,1.300000,0.956572,0.631123,
0.406943,0.305699,0.285317,0.263809,
0.159191,-0.070597,-0.403866,-0.757295,
-1.013795,-1.065855,-0.857949,-0.411682,
0.176336,0.763658,1.207840,1.412279,
1.355387,1.092705,0.731771,0.389703,
0.149857,0.033962,0.000000,-0.033962,
-0.149857,-0.389703,-0.731771,-1.092705,
-1.355387,-1.412279,-1.207840,-0.763658,
-0.176336,0.411682,0.857949,1.065855,
1.013795,0.757295,0.403866,0.070597,
-0.159191,-0.263809,-0.285317,-0.305699,
-0.406943,-0.631123,-0.956572,-1.300000,
-1.544357,-1.582180,-1.358000,-0.893485,
-0.285317,0.323977,0.791865,1.021653,
0.991651,0.757295,0.426010,0.114798,
-0.093107,-0.176103,-0.176336,-0.175872,
-0.256783,-0.461223,-0.767601,-1.092705,
-1.319556,-1.340760,-1.100913,-0.621747,
0.000000,0.621747,1.100913,1.340760,
1.319556,1.092705,0.767601,0.461223,
0.256783,0.175872,0.176336,0.176103,
0.093107,-0.114798,-0.426010,-0.757295,
-0.991651,-1.021653,-0.791865,-0.323977,
0.285317,0.893485,1.358000,1.582180,
1.544357,1.300000,0.956572,0.631123,
0.406943,0.305699,0.285317,0.263809,
0.159191,-0.070597,-0.403866,-0.757295,
-1.013795,-1.065855,-0.857949,-0.411682,
0.176336,0.763658,1.207840,1.412279,
1.355387,1.092705,0.731771,0.389703,
0.149857,0.033962,-0.000000,-0.033962,
-0.149857,-0.389703,-0.731771,-1.092705,
-1.355387,-1.412279,-1.207840,-0.763658,
-0.176336,0.411682,0.857949,1.065855,
1.013795,0.757295,0.403866,0.070597,
-0.159191,-0.263809,-0.285317,-0.305699,
-0.406943,-0.631123,-0.956572,-1.300000,
-1.544357,-1.582180,-1.358000,-0.893485,
-0.285317,0.323977,0.791865,1.021653,
0.991651,0.757295,0.426010,0.114798,
-0.093107,-0.176103,-0.176336,-0.175872,
-0.256783,-0.461223,-0.767601,-1.092705,
-1.319556,-1.340760,-1.100913,-0.621747,
0.000000,0.621747,1.100913,1.340760,
1.319556,1.092705,0.767601,0.461223,
0.256783,0.175872,0.176336,0.176103,
0.093107,-0.114798,-0.426010,-0.757295,
-0.991651,-1.021653,-0.791865,-0.323977,
0.285317,0.893485,1.358000,1.582180,
1.544357,1.300000,0.956572,0.631123,
0.406943,0.305699,0.285317,0.263809,
0.159191,-0.070597,-0.403866,-0.757295,
-1.013795,-1.065855,-0.857949,-0.411682,
0.176336,0.763658,1.207840,1.412279,
1.355387,1.092705,0.731771,0.389703,
0.149857,0.033962,0.000000,-0.033962,
-0.149857,-0.389703,-0.731771,-1.092705,
-1.355387,-1.412279,-1.207840,-0.763658,
-0.176336,0.411682,0.857949,1.065855,
1.013795,0.757295,0.403866,0.070597,
-0.159191,-0.263809,-0.285317,-0.305699,
-0.406943,-0.631123,-0.956572,-1.300000,
-1.544357,-1.582180,-1.358000,-0.893485,
-0.285317,0.323977,0.791865,1.021653,
0.991651,0.757295,0.426010,0.114798,
-0.093107,-0.176103,-0.176336,-0.175872,
-0.256783,-0.461223,-0.767601,-1.092705,
-1.319556,-1.340760,-1.100913,-0.621747,
0.000000,0.621747,1.100913,1.340760,
1.319556,1.092705,0.767601,0.461223,
0.256783,0.175872,0.176336,0.176103,
};
// End of File
四、借助MATLAB计算IIR滤波器系数
首先进入MATLAB的filterDesigner。
滤波器截止频率选择2000Hz,滤除高频噪声,指定阶数为50阶。
将生成的滤波器系数导入到工作区
由于系数在SOS矩阵的行中排序为(b0,b1,b2,1,-a1,-a2),于是我们需要对其第五列与第六列进行取反操作。
这点在MATLAB提供的文档以及TI的例程注释中有提出
MATLAB提供的文档:
TI给出的注释:
G矩阵的元素为每一个对应的二阶节的增益。
编写MATLAB程序,处理导出到工作区的滤波器系数,并保存到本地便于我们后续使用
%将通过filterDesigner生成的SOS、G矩阵处理,保存到本地的coeffs_B.txt、coeffs_A.txt和scaleFactors.txt
SOS_num=size(SOS,1);%获取SOS矩阵的行数
G_num=size(G,1);%获取G矩阵的行数
%对生成的系数A取反
SOS(:,5)=-SOS(:,5);
SOS(:,6)=-SOS(:,6);
%将滤波器设计器生成的滤波器系数打印到coeffs_B,coeffs_A.txt文件中
fileID = fopen('coeffs_B.txt','w');%写文件
for i=1:1:SOS_num
fprintf(fileID,'%6f,%6f,%6f,\n',SOS(i,1),SOS(i,2),SOS(i,3));
end
fclose(fileID);%将生成的初始信号保存到.m文件路径下的coeffs_B.txt
fileID = fopen('coeffs_A.txt','w');%写文件
for i=1:1:SOS_num
fprintf(fileID,'%6f,%6f,%6f,\n',SOS(i,4),SOS(i,5),SOS(i,6));
end
fclose(fileID);%将生成的初始信号保存到.m文件路径下的coeffs_A.txt
%将滤波器设计器生成的比例系数打印到scaleFactors.txt文件中
fileID = fopen('scaleFactors.txt','w');%写文件
TEMP=G(1:G_num-1,1);%取G前G_num-1个数
count=0;
for i=1:1:(G_num-1)
fprintf(fileID,'%6f,',TEMP(i,1));
count=count+1;
if count==3
fprintf(fileID,'\n');%每三个元素后就换行
count=0;
end
end
生成的滤波器系数及对应增益如下:
/*
* Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool
* Generated by MATLAB(R) 9.11 and Signal Processing Toolbox 8.7.
* Generated on: 24-Jul-2023 16:04:36
*/
/*
* 离散时间 IIR 滤波器(实数)
* ----------------
* 滤波器结构 : 直接 II 型,二阶节
* 节数 : 25
* 稳定 : 是
* 线性相位 : 否
*/
/* General type conversion for MATLAB generated C-code */
#define SOS_NUM (25U) // Number of Second Order Stages (biquad)
const float scaleFactors[SOS_NUM]= {0.891251,1.000000,1.000000,
1.000000,1.000000,1.000000,
0.999999,0.999998,0.999996,
0.999990,0.999976,0.999942,
0.999861,0.999668,0.999202,
0.998086,0.995413,0.989026,
0.973869,0.938459,0.858783,
0.694654,0.418945,0.129278,
0.004035,
};
const float coeffs_B[SOS_NUM*3] = {1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984229,1.000000,
1.000000,-1.984228,1.000000,
1.000000,-1.984227,1.000000,
1.000000,-1.984223,1.000000,
1.000000,-1.984214,1.000000,
1.000000,-1.984193,1.000000,
1.000000,-1.984141,1.000000,
1.000000,-1.984016,1.000000,
1.000000,-1.983712,1.000000,
1.000000,-1.982959,1.000000,
1.000000,-1.981005,1.000000,
1.000000,-1.975321,1.000000,
1.000000,-1.952864,1.000000,
1.000000,-1.685740,1.000000,
1.000000,-1.984229,1.000000,
};
const float coeffs_A[SOS_NUM*3] = {1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-1.000000,
1.000000,1.984229,-0.999999,
1.000000,1.984228,-0.999999,
1.000000,1.984227,-0.999997,
1.000000,1.984224,-0.999992,
1.000000,1.984216,-0.999980,
1.000000,1.984197,-0.999953,
1.000000,1.984150,-0.999886,
1.000000,1.984040,-0.999727,
1.000000,1.983777,-0.999348,
1.000000,1.983154,-0.998450,
1.000000,1.981703,-0.996359,
1.000000,1.978466,-0.991696,
1.000000,1.971931,-0.982279,
1.000000,1.961429,-0.967146,
1.000000,1.951510,-0.952853,
1.000000,1.984229,-1.000000,
};
至此已完成了大部分准备工作,接下来开始进行IIR滤波操作。
五、IIR滤波的代码实现
仿照TI给出的例程,完成了以下文件的编写
IIR.h文件
/*
* IIR.h
*
*/
#ifndef APP_IIR_H_
#define APP_IIR_H_
#include "DSP28x_Project.h"
#include <stdio.h>
#include <string.h>
void IIR_filter_run(void);
#endif /* APP_IIR_H_ */
IIR.c文件
/*
* FIR.c
*
* Created on: 2023年7月28日
* Author: yang
*/
#include <IIR.h>
#include "dsp.h"
#include "fpu_filter.h"
#include <math.h>
#include "complex.h"
#include "fdacoefs.h"
#define pi 3.14159
#define IIR_SIZE (512U)
#define NUM_SOS (25U) // Number of Second Order Stages (biquad)
#define FILTER_ORDER (NUM_SOS<<1)
#pragma DATA_SECTION(coeffs_B, "IIR_buffer0");
#pragma DATA_SECTION(coeffs_A, "IIR_buffer0");
#pragma DATA_SECTION(IIR_output, "IIR_buffer1");
// IIR_f32 object
IIR_f32 iir;
// Handle to the IIR_f32 object
IIR_f32_Handle hnd_iir = &iir;
// The filter coefficients and scale factors are tacked on to the end of the
// MATLAB generated input
extern const float coeffs_B[];//系数数组大小在fdacoefs.h中定义,大小为滤波器节数*3
extern const float coeffs_A[];
extern const float scaleFactors[];
// The delay line buffer
float delayLine[NUM_SOS*4U];
float IIR_output[IIR_SIZE];
extern float test_input[];
//*****************************************************************************
// the function definitions
//*****************************************************************************
void IIR_filter_run(void)
{
// Locals
uint16_t i;
float32u_t in, out;
// Configure the object
IIR_f32_setCoefficientsBPtr(hnd_iir, coeffs_B);
IIR_f32_setCoefficientsAPtr(hnd_iir, coeffs_A);
IIR_f32_setDelayLinePtr(hnd_iir, delayLine);
IIR_f32_setInputPtr(hnd_iir, (float *)&in);
IIR_f32_setOutputPtr(hnd_iir, (float *)&out);
IIR_f32_setScalePtr(hnd_iir, scaleFactors);
IIR_f32_setOrder(hnd_iir, FILTER_ORDER);
IIR_f32_setInitFunction(hnd_iir, (v_pfn_v)IIR_f32_init);
IIR_f32_setCalcFunction(hnd_iir, (v_pfn_v)IIR_f32_calc);
// Run the initialization function
hnd_iir->init(hnd_iir);
for(i = 0U; i < IIR_SIZE; i++)
{
out.f32 = FLT_MAX;
in.f32 = test_input[i];
// Call the calculation routine
hnd_iir->calc(hnd_iir);
IIR_output[i] = out.f32;
}
}
// End of File
由于笔者使用了自定义段,故要在cmd文件中分配其对于的存储空间。Cmd文件如下:
/*
// TI File $Revision: /main/3 $
// Checkin $Date: July 9, 2008 14:12:45 $
//###########################################################################
//
// FILE: 28335_RAM_lnk.cmd
//
// TITLE: Linker Command File For IQmath examples that run out of RAM
//
// NOTE; The example project uses memory protected by the
// Code Security Module (CSM). Make sure the CSM is
// unlocked before you load the project. One quick way
// to do this on an erased device is to open a memory
// window to the CSM password locations. If these locations
// read back 0xFFFF (or non-zero), then the CSM is unlocked:
//
// Device Password locations
// 28335: 0x33FFF8 - 0x33FFFF
//
//###########################################################################
//
//
// $Copyright: Copyright (C) 2014-2022 Texas Instruments Incorporated -
// http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################
*/
MEMORY
{
PAGE 0 :
BEGIN : origin = 0x000000, length = 0x000002 /* Boot to M0 will go here */
BOOT_RSVD : origin = 0x000002, length = 0x00004E /* Part of M0, BOOT rom will use this for stack */
RAML0 : origin = 0x008000, length = 0x000800
RAML1L2 : origin = 0x008800, length = 0x004800
ZONE7A : origin = 0x200000, length = 0x00FC00 /* XINTF zone 7 - program space */
FLASHH : origin = 0x300000, length = 0x008000 /* on-chip FLASH */
FLASHG : origin = 0x308000, length = 0x008000 /* on-chip FLASH */
FLASHF : origin = 0x310000, length = 0x008000 /* on-chip FLASH */
FLASHE : origin = 0x318000, length = 0x008000 /* on-chip FLASH */
FLASHD : origin = 0x320000, length = 0x008000 /* on-chip FLASH */
FLASHC : origin = 0x328000, length = 0x008000 /* on-chip FLASH */
FLASHA : origin = 0x338000, length = 0x007F80 /* on-chip FLASH */
CSM_RSVD : origin = 0x33FF80, length = 0x000076 /* Part of FLASHA. Program with all 0x0000 when CSM is in use. */
CSM_PWL : origin = 0x33FFF8, length = 0x000008 /* Part of FLASHA. CSM password locations in FLASHA */
OTP : origin = 0x380400, length = 0x000400 /* on-chip OTP */
ADC_CAL : origin = 0x380080, length = 0x000009
IQTABLES : origin = 0x3FE000, length = 0x000b50 /* IQ Math Tables in Boot ROM */
IQTABLES2 : origin = 0x3FEB50, length = 0x00008c /* IQ Math Tables in Boot ROM */
FPUTABLES : origin = 0x3FEBDC, length = 0x0006A0 /* FPU Tables in Boot ROM */
ROM : origin = 0x3FF27C, length = 0x000D44 /* Boot ROM */
RESET : origin = 0x3FFFC0, length = 0x000002
VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM */
PAGE 1 :
BOOT_RSVD : origin = 0x000002, length = 0x00004E /* Part of M0, BOOT rom will use this for stack */
RAMM0 : origin = 0x000050, length = 0x0003B0 /* on-chip RAM block M0 */
RAMM1 : origin = 0x000400, length = 0x000400 /* on-chip RAM block M1 */
RAML3 : origin = 0x00D000, length = 0x001000
RAML4 : origin = 0x00E000, length = 0x001000
RAML5 : origin = 0x00F000, length = 0x001000
ZONE7B : origin = 0x20FC00, length = 0x000400 /* XINTF zone 7 - data space */
FLASHB : origin = 0x330000, length = 0x008000 /* on-chip FLASH */
}
SECTIONS
{
FPUmathTables : > FPUTABLES, PAGE = 0, TYPE = NOLOAD
/* Setup for "boot to SARAM" mode:
The codestart section (found in DSP28_CodeStartBranch.asm)
re-directs execution to the start of user code. */
codestart : > BEGIN, PAGE = 0
#ifdef __TI_COMPILER_VERSION__
#if __TI_COMPILER_VERSION__ >= 15009000
.TI.ramfunc : {} LOAD = RAML0,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
LOAD_SIZE(_RamfuncsLoadSize),
PAGE = 0
#else
ramfuncs : LOAD = RAML0,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
LOAD_SIZE(_RamfuncsLoadSize),
PAGE = 0
#endif
#endif
.text : {*(.text)}>> RAML1L2|RAML0 PAGE = 0
.cinit : > RAML0, PAGE = 0
.pinit : > RAML0, PAGE = 0
.switch : > RAML0, PAGE = 0
.stack : > RAMM1, PAGE = 1
.ebss : > RAML3, PAGE = 1
.econst : > RAML3, PAGE = 1
.sysmem : > RAML3, PAGE = 1
.esysmem : > RAML3, PAGE = 1
.sysmem : > RAML3, PAGE = 1
IIR_buffer0 : > RAML4, PAGE = 1
IIR_buffer1 : > RAML5, PAGE = 1
.cio : > RAML3, PAGE = 1
ZONE7DATA : > ZONE7B, PAGE = 1
DMARAML4 : > RAML4, PAGE = 1
DMARAML5 : > RAML5, PAGE = 1
.reset : > RESET, PAGE = 0, TYPE = DSECT /* not used */
csm_rsvd : > CSM_RSVD PAGE = 0, TYPE = DSECT /* not used for SARAM examples */
csmpasswds : > CSM_PWL PAGE = 0, TYPE = DSECT /* not used for SARAM examples */
/* Allocate ADC_cal function (pre-programmed by factory into TI reserved memory) */
.adc_cal : load = ADC_CAL, PAGE = 0, TYPE = NOLOAD
}
/*
//===========================================================================
// End of file.
//===========================================================================
*/
在主函数中,我们调用IIR_filter_run();函数即可完成滤波操作。
借助CCS的Graph画图工具测试滤波效果如下:
原始信号:
滤波后的1KHz信号:
可以看到IIR数字滤波器滤除了5KHz与10KHz的信号,仅保留了1KHz的信号(图中信号1个完整周期的采样点数为100点,滤波后信号幅度约为0.3,与理论值相符),从而验证滤波结果的准确性。