测量谐波-STM32L4 Discovery的频谱分析仪

在上一篇文章中,我们将廉价的中文LCD屏幕连接到STM32L4 Discovery板上现在,我们将尝试实现这种组合,这超出了传统的LED闪烁功能,即使用板载麦克风的声谱分析仪。同时,我将告诉您如何使用FreeRTOS操作系统,为什么需要它,以及为什么在一个音乐八度音阶中有12个音符,而53个音符比12个音符好。





声音数字化


我们希望接收来自麦克风的信号,使用快速傅立叶变换(FPU帮助我们)计算其频谱,并以“颜色瀑布”的形式在LCD上显示结果。声音强度将以颜色编码。我们将从显示器的边缘绘制一条像素线,其中最左边的像素将对应于最小频率,最右边的像素将对应于最大频率,而上一张图片将移动一行,从而为新行腾出空间。我们的微控制器太复杂了,无法从头开始,所以让我们从STM32Cube套件中的一个名为DFSDM_AudioRecord的示例开始。什么是DFSDM?这是用于Sigma-Delta调制的数字滤波器。事实是,与老式的模拟麦克风不同,发现板上的麦克风不会以与声压成比例的电压形式发出信号,以及零和一的序列,其时钟频率为几兆赫。如果将此序列通过低通滤波器,则会得到相同的模拟信号。在以前的微控制器模型中,有必要制作一个数字滤波器以接收数字形式的音频信号。现在,微控制器为此提供了一个特殊的模块,所需要的只是在程序开始时对其进行配置。为此,您可以阅读文档或使用现成的示例。我走了第二条路。下图说明了DFSDM_AudioRecord程序的内部结构。在以前的微控制器模型中,有必要制作一个数字滤波器以接收数字形式的音频信号。现在,微控制器为此提供了一个特殊的模块,所需要的只是在程序开始时对其进行配置。为此,您可以阅读文档或使用现成的示例。我走了第二条路。下图说明了DFSDM_AudioRecord程序的内部结构。在以前的微控制器模型中,您必须制作一个数字滤波器才能获得数字声音信号。现在,微控制器为此提供了一个特殊的模块,所需要的只是在程序开始时对其进行配置。为此,您可以阅读文档或使用现成的示例。我走了第二条路。下图说明了DFSDM_AudioRecord程序的内部结构。



使用DMA的数字化声音落入环形缓冲区。DMA产生两次中断:一次-当缓冲区已满一半时,第二次-当缓冲区已满时。中断例程仅设置适当的标志。初始化之后的main()函数执行一个无限循环,在该循环中检查这些标志,如果设置了标志,则将复制缓冲区的相应一半。一个示例将数据复制到另一个缓冲区,然后再次使用DMA从该缓冲区将其发送到耳机放大器。我离开了此功能,添加了音频信号频谱的计算。

有很多任务时


向我们的代码添加新功能的直接方法是添加更多标志,并编写设置了这些标志时将调用的函数。结果通常是混乱的标志,处理程序函数和全局上下文,它们被迫是全局的,因为一个问题的解决方案分为由各个函数-事件处理程序实现的许多小步骤。另一种方法是将任务管理委托给操作系统,例如FreeRTOS。由于每个任务都是在其自己的事件处理周期内解决的,因此可以大大简化逻辑,这些事件通过操作系统的功能相互交互。例如,我们可以将数据处理任务添加为一个单独的周期,它将等待同步原语-信号量上的数据准备就绪。信号量非常简单:如果选中该标志,则可以通过它,并且该标志会自动省略。在我们的例子中,数据源在为其他任务准备数据时将发出一个标志。以类似的方式,您可以从数据源任务和数据使用者任务创建任意链,类似于这在Linux操作系统中的发生方式。在Linux操作系统中。在Linux操作系统中。



当然,同时执行任务是一种错觉,尤其是在计算核心只有一个的情况下。在这种情况下,我们可以说处理器只有一个线程执行程序。像其他同步原语一样,信号量扮演着一个神奇的兔子洞的角色,在另一个任务中执行流无法出现。

将FreeRTOS连接到您的项目非常简单。只需用对osKernelStart()的调用来代替通常在微控制器中结束main()函数的无限循环。之后,编译器将向您确切解释编译所缺少的内容。您先前在循环中执行的所有操作都需要转移到一个单独的任务中,并通过xTaskCreate调用进行注册。之后,您可以根据需要添加更多任务。应当记住,最好不要在xTaskCreate和osKernelStart调用之间放置任何硬件代码,因为系统计时器在此处可能无法正常工作。必须将对osSystickHandler()操作系统计时器处理程序的调用添加到SysTick_Handler()中,并且应将两个函数SVC_Handler和PendSV_Handler从其代码中删除,因为它们是在OS代码中实现的。注册任务时,重要的是不要弄错堆栈的大小。如果结果太小,则会在最意想不到的地方崩溃。当堆栈溢出时,第一个是描述任务的结构本身。 IAR可以查看任务列表。如果您看到任务名称更改,则需要增加堆栈的大小。


要计算频谱,我们使用快速傅立叶变换。相应的功能已经在库中。她接收到一个充满复杂数据的缓冲区,并在那里形成结果。因此,在输入处,她需要一个缓冲区,其中数字化的声音以零交替(复杂部分0)。在输出中,我们得到复数,我们可以通过将实部和虚部的平方相加立即计算出模块的平方。因为频谱是对称的,所以我们仅对一半的缓冲区执行此操作。如果要进行逆变换,则需要后半部分,但是对于频谱的简单显示,则不需要。为了能够计算不同光谱范围内的光谱,需要付出一些额外的努力。要获得低频频谱,我在读取缓冲区的几个周期中积累了数据,有效地降低了声音的采样频率,最初是44.1kHz。结果是6个范围-20kHz,10kHz,5kHz,2600Hz,1300Hz,650Hz。要切换范围,请使用操纵杆和单独的任务。操纵杆还具有启动/停止“瀑布”的功能以及调节灵敏度的功能。以对数单位(分贝)显示频谱更方便,因为它的动态范围通常很大,并且在线性范围内,我们只能分辨出频谱中最强的成分。即使在FPU上,对数也被认为是相当长的时间,所以我用分段线性近似代替了实数,很容易获得,知道结果是6个范围-20kHz,10kHz,5kHz,2600Hz,1300Hz,650Hz。要切换范围,请使用操纵杆和单独的任务。操纵杆还具有启动/停止“瀑布”的功能以及调节灵敏度的功能。以对数单位(分贝)显示频谱更方便,因为它的动态范围通常很大,并且在线性范围内,我们只能区分频谱中最强的分量。即使在FPU上,对数也被认为是相当长的时间,所以我用分段线性近似代替了实数,很容易获得,知道结果是6个范围-20kHz,10kHz,5kHz,2600Hz,1300Hz,650Hz。要切换范围,请使用操纵杆和单独的任务。操纵杆还具有启动/停止“瀑布”的功能以及调节灵敏度的功能。以对数单位(分贝)显示频谱更方便,因为它的动态范围通常很大,并且在线性范围内,我们只能分辨出频谱中最强的成分。即使在FPU上,对数也被认为是相当长的时间,所以我用分段线性近似代替了实数,很容易获得,知道以对数单位(分贝)显示频谱更方便,因为它的动态范围通常很大,并且在线性范围内,我们只能分辨出频谱中最强的成分。即使在FPU上,对数也被认为是相当长的时间,所以我用分段线性近似代替了实数,很容易获得,知道以对数单位(分贝)显示频谱更方便,因为它的动态范围通常很大,并且在线性范围内,我们只能分辨出频谱中最强的成分。即使在FPU上,对数也被认为是相当长的时间,所以我用分段线性近似代替了实数,很容易获得,知道表示float32中数字的格式最重要的是一个标志。接下来的8位是二进制指数加127。其余部分是尾数的小数部分,尽管整数部分为1(为简单起见,我们忽略了非规格化数字的细微差别)。因此,从float32中选择了指数并获取了尾数的几个最高有效位,就可以很好地近似对数。使用预先准备的表格,我们将结果编号转换为RGB代码以在LCD上显示。结果是90或60分贝的色标。可以通过上下推操纵杆来调节与该刻度的零相对应的音量。

我们展示一幅图片-关于阅读数据表的好处


现在我们只需要显示图片并恢复我们的“瀑布”即可。这样做的直接方法是将整个屏幕上的图像存储在缓冲区中,在那里进行更新,并在每次出现新数据时重新绘制。这种解决方案不仅效率极低,而且我们也没有足够的内存来存储整个图片。 LCD本身似乎有足够的存储空间,因此应该可以做一些有趣的事情。确实,数据表的研究允许检测迄今为止尚未使用的滚动命令,该命令可让您动态更改LCD控制器内存在屏幕上的显示方式。想象一下,内存是一个绑在环形玻璃中的磁带,您可以在屏幕玻璃下面看到它。“垂直滚动起始地址(0x37)”命令使您可以设置功能区上与屏幕顶部边缘相对应的位置。因此,要恢复“瀑布”,我们所需要做的就是在此位置记录一个新频谱并滚动浏览存储磁带。相应的代码已添加到LCD驱动程序,并从著名的Peter Drescher借来,并按此处所述进行了修改这种方法的唯一缺点是:滚动只能沿屏幕的长边进行。因此,只有短边可用于频谱输出。

12 ?


让我们继续进行设备的实际应用。在频谱上最容易看到的第一件事是谐波,即,频率是基频的倍数。尤其是其中很多人的声音。声音中也有乐器。很容易理解为什么相邻八度音符的频率相差2倍:然后,高八度音符的频率与低八度音符的二次谐波重合。他们说同时他们听起来“一致”。很难理解为什么一个八度音阶中有12个音符-7个主音(钢琴键盘上的白色键)加上5个附加音符(黑色键)。主音符用尖锐且扁平的字符表示附加音符,尽管实际上它们与主音符没有区别-所有12个音符形成几何级数,因此相邻音符之间的频率比率等于12度2的根。将此八度音阶划分为音符的含义是,对于任何音符,还有其他音符的​​频率相差一倍半-这种组合称为第五音符。组成第五个音符的音符会统一发声,因为一个音符的二次谐波的频率与另一个音符的三次谐波的频率重合。下图显示了音符Do和Sol的光谱,形成第五个,匹配的谐波以黄色圈出。形成第五个,匹配的谐波以黄色圈出。形成第五个,匹配的谐波以黄色圈出。



笔记12怎么来了?由于音符形成几何级数,因此我们继续对数。ln(1.5)/ ln(2)= 0.58496 ...获得分数7/12 = 0.583的接近值...也就是说,结果发现七个半音(相邻音符之间的间隔)非常接近五重奏-1.498。有趣的是,分数31/53 = 0.58491 ..给出了更高的精度,因此第五位仅在第五位小数处与1.5不同。这个事实并没有引起人们的注意,但是在八度音阶中有53个音符的乐器并没有得到分配。它们很难调音,很难演奏,并且能感觉到与传统工具不同的人的百分比正在逐渐减少。

源代码


躺在这里为了进行编译,使用了用于ARM 7.50.2的IAR嵌入式工作台。编译不需要其他库。

Source: https://habr.com/ru/post/zh-CN391311/


All Articles