arm-dsp库官方已经封装好了,使用的时候需要把dsp库移植到工程里面,具体怎么移植网上可以找到教程
这里直接说怎么用FIR的流程:
一、Matlab里面生成所配置的阶数和系数
1、在Matlab命令窗口输入fdatool,回车,会弹出一个新窗口
2、在新窗口中的响应类型选择【低通】,设计方法选择【 FIR里面的最平坦】,滤波器阶数选择【指定阶 80】(这里以80举例),频率设置选择【Hz,Fs3200,Fc200】(同样也是举例,后面自己按照需求改动),选择完后点击设计滤波器,并在上方【编辑】中点击【转换结构】选择【Direct-Form FIR】在点击确认
3、在上方选择【目标】中的【生成C的头文件】 ,改变导出类型为【单精度浮点】,然后点击生成保存到文件夹中
二、在keil 写相关程序
主要是用到了dsp库里面这两个函数
我们先把要处理的数据放进一个数组,我自己使用的ADC采集信号发生器发出的基频为100Hz的信号。
将ADC采集的数据转换为电压存入一个数组中
uint32_t i=0; for(i=0;i<256;i++) { inbuf[i]=(float)(ADC1_ConvertedValue[i]*3.3/4096); }
接下来就要配置上面用的函数了
//FIR实例化结构体 arm_fir_instance_f32 * S;
还记得刚刚Matlab生成的文件吗?打开这个文件,复制这些到工程里面去。
//FIR滤波器系数个数 uint16_t numTaps=81;
//FIR滤波器系数 float32_t pCoeffs[81]={ 3.671998324e-22,2.631265729e-20,9.278031016e-19, 2.14557019e-17,3.659253801e-16, 4.907191783e-15,5.387333849e-14, 4.97747839e-13,3.948472625e-12,2.730093235e-11, 1.664632598e-10,9.033196413e-10,4.394613118e-09,1.927893756e-08,7.661567736e-08, 2.767831404e-07,9.112107477e-07,2.737595878e-06,7.507435839e-06,1.876901842e-05, 4.263511073e-05,8.741336933e-05,0.0001597262308,0.0002535805688,0.0003294369671, 0.0002852701291,-6.710144226e-05,-0.0009913889226,-0.002741852077, -0.00537379086, -0.00846511405, -0.01084412821, -0.01049835142,-0.004857060499, 0.008461467922, 0.03057124838, 0.0603001751, 0.09375944734, 0.1249034405, 0.1470876038, 0.1551340818, 0.1470876038, 0.1249034405, 0.09375944734, 0.0603001751, 0.03057124838, 0.008461467922,-0.004857060499, -0.01049835142, -0.01084412821, -0.00846511405, -0.00537379086,-0.002741852077,-0.0009913889226,-6.710144226e-05, 0.0002852701291,0.0003294369671,0.0002535805688,0.0001597262308,8.741336933e-05, 4.263511073e-05,1.876901842e-05,7.507435839e-06,2.737595878e-06,9.112107477e-07, 2.767831404e-07,7.661567736e-08,1.927893756e-08,4.394613118e-09,9.033196413e-10, 1.664632598e-10,2.730093235e-11,3.948472625e-12, 4.97747839e-13,5.387333849e-14, 4.907191783e-15,3.659253801e-16, 2.14557019e-17,9.278031016e-19,2.631265729e-20, 3.671998324e-22 };
//FIR滤波器状态变量暂存:数组的大小=numTaps+blocksize-1 float32_t pState[336]={0.0f};
//块处理大小 uint32_t blockSize=256;
//输入数据 float32_t inbuf[256]={0}; //输出数据 float32_t outbuf[256]= {0};
接下来就要调用上面说的函数了,不过我们先要为arm_fir_instance_f32这个结构体开辟一个空间
// 为FIR实例分配内存 S = (arm_fir_instance_f32 *)malloc(sizeof(arm_fir_instance_f32)); if (S == NULL) { // 内存分配失败,处理错误 return; }
malloc和free这两个函数需要包含#include <stdlib.h>这个头文件,不然会报错
这行代码 S = (arm_fir_instance_f32 *)malloc(sizeof(arm_fir_instance_f32));
是C语言中动态内存分配的一个常见用法。这行代码做了以下几件事情:
sizeof(arm_fir_instance_f32)
:计算arm_fir_instance_f32
结构体类型所占用的字节数。malloc(sizeof(arm_fir_instance_f32))
:调用malloc
函数,请求分配足够存储一个arm_fir_instance_f32
结构体的内存空间。malloc
返回的是一个指向所分配内存区域的void
指针。(arm_fir_instance_f32 *)
:将void
指针强制类型转换为arm_fir_instance_f32
指针。这是因为malloc
返回的是void
指针,而我们需要一个指向arm_fir_instance_f32
的指针来操作分配的内存。S = ...
:将转换后的指针赋值给S
,这样S
现在就指向了一块新分配的内存,这块内存足够存储一个arm_fir_instance_f32
实例。
重要的是要注意,在使用malloc
分配内存之后,你有责任在不再需要这块内存时使用free
函数来释放它,以避免内存泄漏。
另外,务必检查malloc
的返回值是否为NULL
。如果malloc
无法分配所需的内存(例如,由于内存不足),它将返回NULL
。在这种情况下,你应该处理这个错误情况,而不是尝试使用NULL
指针,因为这会导致程序崩溃。
现在再调用那两个函数
arm_fir_init_f32(S,numTaps,pCoeffs,pState,blockSize); arm_fir_f32(S,inbuf,outbuf,blockSize);
这样在outbuf数组中就是低通滤波后的数据了
最后我们使用free函数释放内存,避免内存泄漏
free(S); // 释放内存 S = NULL; // 将指针设置为 NULL,以避免悬挂指针
OK,用串口打印出来看看效果
蓝色的方波是原始信号,橙色的正弦波是经过低通滤波的信号,效果还是ok的
到此,就完成了软件滤波