一、前言
这是前两天搭建的H7B0单片机信号采集与计算的模块,利用它的16比特的ADC采集信号,并进行频谱分析,结果显示在OLED屏幕上。计算 2048点的FFT,耗时大约为 10个毫秒左右。下面测试一下,利用 Cortex中的 CMSIS中的 DSP算法库中的FFT,看是否计算速度能够得到提高,并对比计算的结果的精度,下面进行测试。
首先点击 Keil 编译环境中的 Package 按键,打开软件包管理单元。添加 CMSIS 中的 Core以及 DSP 软件包。确定之后,便可以在工程文件后面看到对应的 DSP软件包了。
在工程选项中,C++设置页面,增加 ARM_MATH_CM7 这个常量,表示使用对应Cortext-M7 内核的DSP算法库。在应用 C 文件中,增加相应的头文件,这里增加两个头文件。请注意,如果不增加前面 ARM_MATH_CM7常量的定义,在包含头文件之后,就会出现编译出错。下面就可以应用相应的DSP函数了。
调用DSP中的实数浮点FFT函数,对 长度为 2048 的浮点数组进行初始化,前面四个数字设置 1,其他都是0。初始化FFT实例参数,进行实数FFT变换,计算FFT结果的赋值。进行结果显示和图像绘制。
这是进行FFT数据的波形,在前面 4 个数据,幅度为 1,其他都是0,变换结果中,前面一半是数据的幅度频谱,对于实数来讲,它的幅度谱关于中心店左右对称,输出结果中,只给出了前面一半的结果,后面一半不是计算的数据。这里需要说明的是,FFT计算是即位存储,也就是最终的结果存储在输入数据存储区中。输出结果只有实际频谱的前半段,后半段与前半段呈现共轭对称。
▲ 图1.3.1 信号的波形
▲ 图1.3.2 变换后的幅度谱
对比单片机DSP库计算得到的幅度谱与 Python 计算的幅度谱,它们是重合的,对应的误差应该是反映了单精度浮点数与双精度浮点数之间的差异性。
▲ 图1.3.3 绘制DSP与Python 计算的结果
▲ 图1.3.4 DSP与Python 计算幅度品的误差
但是,遇到了一个诡异的情况,那就是如果设置数据窗口长度为5,DSP计算的结果的第一个数值就会出现较大的误差。第一个数字反映了数据的直流分量。这是数据窗口长度为 7 的时候,也是出现了较大的误差。这就是了怪了,窗口长度为偶数的时候是准确的,是奇数的时候不准确,这个问题困扰了我很长时间,不知道谁能够给出解答。
▲ 图1.3.5 当数据窗口宽度为5的时候,计算结果的第一位,也就是直流分量结果出现了较大的误差
绘制出数据窗口的宽度从0 到 2048 过程中,DSP算法库得到的结果第一个数据对应的误差。随着数据的长度增加,误差减小。误差与数据的长度成反比。对应的窗口为偶数的时候,误差为0,奇数的时候出现了差异。这实在令人感到奇怪了。
▲ 图1.3.6 不同窗口计算出的直流分量的误差分布
为了测量DSP中的FFT计算速度,在FFT函数调用前后增加对单片机端口 的操作,有单片机端口的高低电平来表示FFT的计算时间, 通过示波器,测量该端口的波形,可以确定 DSP 库中的FFT的计算速度。单片机时钟频率设为 280MHz,对于长度为 2048 的 FFT,单片机计算时间长度为 1.22ms。前两天自行编写了 FFT C语言算法,同样长度,需要大约 10ms的时间。课件 DSP库中的算法效率还是非常高的。
▲ 图1.4.1 计算速度
本文对于STM32H7B0单片机使用DSP算法库进行 FFT计算进行测测试。速度非常快,对于2048个数据进行单精度浮点计算时,耗时大约为 1.2ms,这是内核时钟频率为 280MHz 的情况下测量的。但也出现了一个令人不解的情况,那就是计算直流量在某些情况下会出现误差。具体原因现在还不清楚呢。
STM32 DSP库的使用方法: https://blog.csdn.net/u010058695/article/details/112665306
[2]模拟信号的采集并显示频谱:STM32H7B0: https://zhuoqing.blog.csdn.net/article/details/136419754
[3]STM32H7B0模块的电路图: https://zhuoqing.blog.csdn.net/article/details/136285749