测试工程:
定点Q31 IIR滤波.7z (4.70MB)
测试波形是50Hz和200Hz正弦波,采样率设置的1KHz,IIR低通的截止频率设置的80Hz。
Matlab设置如下(详细设置看DSP教程第2版的IIR章节即可,生成方法不变):
将生成的参数代入到工程代码,滤波输出效果如下,未做定标处理
滤波效果是没问题的,完全正常(简单做了放缩处理,方便观察)
代码如下:
由于我们继续使用的浮点生成的系数,这个系统不能直接使用,需要先缩小,防止溢出,然后再调用函数arm_float_to_q31加大。
最后再配合函数arm_biquad_cascade_df1_init_q31做调整
[C] 纯文本查看 复制代码 #define numStages 5 /* 5阶IIR滤波的个数 */
#define TEST_LENGTH_SAMPLES 400 /* 采样点数 */
#define BLOCK_SIZE 400 /* 调用一次arm_biquad_cascade_df1_f32处理的采样点个数 */
uint32_t blockSize = BLOCK_SIZE;
uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE; /* 需要调用arm_biquad_cascade_df1_f32的次数 */
/////////////////////////////////////// 定点Q31 /////////////////////////////////////////////////////////////////////////
static q31_t testInput_f32_50Hz_200Hz1[TEST_LENGTH_SAMPLES]; /* 采样点 */
static q31_t testOutput1[TEST_LENGTH_SAMPLES]; /* 滤波后的输出 */
static q31_t IIRStateF321[4*numStages]; /* 状态缓存 */
q31_t IIRCoeffs32LP1[5*numStages];
/* 巴特沃斯低通滤波器系数 80Hz*/
float32_t IIRCoeffs32LP[5*numStages] = {
1, 2, 1, 1.62978785624054456349085739930160343647, -0.85983730736705732411451208463404327631,
1, 2, 1, 1.438087052475096605519411241402849555016, -0.641077359359069620658999610895989462733,
1, 2, 1, 1.307285028849323404998017394973430782557, -0.491812237222575276973657310009002685547,
1, 2, 1, 1.226250602643673470737439856748096644878, -0.39933955836362394764549321735103148967,
1 , 2, 1, 1.187550247801674174752406543120741844177, -0.355176532195590921592298627729178406298
};
/*
*********************************************************************************************************
* 函 数 名: arm_iir_q31_lp
* 功能说明: 调用函数arm_iir_q31_lp实现低通滤波器
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void arm_iir_q31_lp(void)
{
uint32_t i;
arm_biquad_casd_df1_inst_q31 S;
q63_t ScaleValue;
q31_t *inputQ31, *outputQ31;
/* 使用浮点系数先进行一次缩放,然后再使用函数arm_float_to_q31转换为Q31,防止溢出 */
for(int i = 0; i < 5*numStages; i++)
{
IIRCoeffs32LP[i] = IIRCoeffs32LP[i]/8;
}
arm_float_to_q31(IIRCoeffs32LP, IIRCoeffs32LP1, 5*numStages);
for(int i = 0; i < 5*numStages; i++)
{
//printf("%d\r\n", IIRCoeffs32LP1[i]);
}
/* 初始化输入输出缓存指针 */
inputQ31 = &testInput_f32_50Hz_200Hz1[0];
outputQ31 = &testOutput1[0];
for(i=0; i<TEST_LENGTH_SAMPLES; i++)
{
/* 50Hz正弦波+200Hz正弦波,采样率1KHz */
testInput_f32_50Hz_200Hz1[i] = arm_sin_q31(2147483647/1000*50*i) / 16 + arm_sin_q31(2147483647/1000*200*i)/16;
}
/* 初始化,根据系数的缩放,此函数的最后一个参数要做调整 */
arm_biquad_cascade_df1_init_q31(&S, numStages, (q31_t *)&IIRCoeffs32LP1[0], (q31_t *)&IIRStateF321[0], 1);
/* 实现IIR滤波,这里每次处理1个点 */
for(i=0; i < numBlocks; i++)
{
arm_biquad_cascade_df1_q31(&S, inputQ31 + (i * blockSize), outputQ31 + (i * blockSize), blockSize);
}
/* 放缩系数,testOutput1乘以放缩系数才是准确的 */
//0.057512362781628162400338055704196449369
//0.050747576720993219090427572837143088691
//0.046131802093312926360546555315522709861
//0.043272238929987591471437724521820200607
//0.041906571098479158954397405523195629939
/* 打印滤波后结果 */
for(i=0; i<TEST_LENGTH_SAMPLES; i++)
{
printf("%d, %d\r\n", testInput_f32_50Hz_200Hz1[i], testOutput1[i]);
}
}
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: c程序入口
* 形 参: 无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ucKeyCode; /* 按键代码 */
bsp_Init(); /* 硬件初始化 */
PrintfLogo(); /* 打印例程信息到串口1 */
PrintfHelp(); /* 打印操作提示信息 */
bsp_StartAutoTimer(0, 100); /* 启动1个100ms的自动重装的定时器 */
/* 进入主程序循环体 */
while (1)
{
bsp_Idle(); /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
if (bsp_CheckTimer(0)) /* 判断定时器超时时间 */
{
/* 每隔100ms 进来一次 */
bsp_LedToggle(2); /* 翻转LED的状态 */
}
ucKeyCode = bsp_GetKey(); /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1: /* K1键按下 */
arm_iir_q31_lp();
break;
default:
/* 其它的键值不处理 */
break;
}
}
}
}
|