FPGA实时光谱仪
实时频谱图项目可以在标准VGA监视器上计算和显示音频信号的频谱。
该系统使用包含Altera Cyclone II FPGA 的Altera DE2原型开发板。使用8 kHz的板载模数转换器对音频进行采样。频谱以32 Hz频率区间的分辨率线性分布,从0 Hz到4 kHz。使用32个带通滤波器计算频谱,并以640 x 480分辨率输出到全彩色VGA显示器。界面由滚动频谱图和实时幅度条形图组成。
Tim Schofield(tjs49)
Adrian Wong(aw259)
高级设计
傅里叶变换 | 离散傅里叶变换 | 快速傅里叶变换 | VGA显示器 | HSL颜色
可以使用两种不同的方法来计算频谱图上显示的频率内容。第一个使用傅里叶变换,第二个使用一组带通滤波器。在这个项目中尝试了这两种技术。
傅里叶变换
傅里叶变换将信号从时域映射到频域。得到的频谱显示原始信号的频率成分。傅里叶变换基于将信号分解为由傅里叶级数形成的无限正交基函数集。傅立叶变换的具体数学细节可以在任何数量的在线参考文献中找到(例如Mathworld)。
离散傅立叶变换
快速傅里叶变换利用称为离散傅里叶变换(DFT)的离散时间有限域傅立叶变换。
离散傅立叶变换用于输入信号,其在时间上是离散的并且具有有限的持续时间(有限域)。DE2上的音频编解码器生成一个采样波形,该波形在时间上是离散的(样本不连续)和有限持续时间(波形持续时间是有限的)。
DFT将N个复数(x 0,x 1,...,x n-1)的输入序列转换为N个复数(X 0,X 1,...,X n-1)的输出序列。DFT由等式1给出。
指数因子通常被称为旋转因子,并用以下符号表示。
DFT可以被认为是匹配滤波器,其将输入信号x n与由旋转因子W(nk,N)给出的正交的正弦基函数集合进行卷积。
应注意,由于输入序列是实值的,因此输入的复杂分量始终为零。结果,DFT的复数输出频率关于奈奎斯特频率(采样频率的一半)对称。有关更多详细信息,请考虑访问有关奈奎斯特 - 香农采样定理和混叠的参考文本。
在频谱图的情况下,输入序列可以被认为是来自音频编解码器的一组实值样本,并且输出序列是信号的频率分量的集合。更具体地说,设N为64,采样频率为48 kHz。这意味着输入是64个音频波形样本,输出是64个等间隔频率区间,从0到48 kHz为750 Hz。24 kHz至48 kHz的频率是0 Hz至24 kHz频率的重复频率。
快速傅里叶变换
DFT是计算密集型的。从等式1可以看出,每个频率分量X(k)需要N次复数乘法和N次复数加法。存在N个频率分量,因此N点DFT需要2N 2个复数运算(N 2乘法,N 2个和)。在大O表示法中,DFT具有O(N 2)的计算复杂度。
快速傅里叶变换使用多个优化来将操作数减少到O(N log N)。
抽取(分而治之)
将长度为8的DFT分解为两个长度为4的DFT。
(来源:Connexions)
最重要的优化之一是抽取。出于说明的目的,基数2抽取时间算法示出了如何简化DFT以形成FFT。
基数-2 DIT FFT算法首先将N点DFT分成两个长度为N / 2的DFT。所有奇数编号的标记都用一个DFT分组,所有偶数编号的索引用另一个DFT分组。
这被称为radix-2 DFT,因为有两个组,它被称为时间抽取,因为时域样本的索引是重新排列的。还有更高的基数算法(例如radix-4)以及频率抽取算法(其中频率区间需要重新排序)。
只用一个阶段基2简单化的减少复杂的操作,以N + N数2 /2次复数乘法和N 2 /2次复数加法。递归地应用基数-2 DFT产生O(N log N)结果。
进一步分解DFT
(来源:Connexions)
通过转换到可以在FPGA上更有效地计算的基数,可以进一步节省成本。Radix-4特别有用,因为每个DFT内的旋转因子只是乘以±1或±j。
对于实际的复数乘数,可以使用更多的优化。有关更多信息,请参阅radix-4 DFT实现详细信息。
带通滤波器
第二种方法是使用一组带通滤波器。这些带通滤波器可以在起始频率和奈奎斯特频率之间线性或对数地间隔开。每个带通滤波器构成频谱图中的单个频率仓。乘法器的数量随着频谱图中频段的频率数量而缩放为O(N)。
VGA显示
滚动视频
我们项目的一个主要组成部分是平滑滚动频谱图,在可调节的时间窗口内显示32个频率的大小。在项目开始时,我们意识到我们希望我们的时间窗口不断更新而不是填充,然后冻结或清除。但是,我们还必须考虑到,在同步期间,我们很可能无法以视频速率移动大块视频SRAM,这标志着我们的第一个概念障碍。
相反,我们开始将视频SRAM视为列的圆形矢量。然后我们意识到我们可以使用一些任意指针或 offset 来标记屏幕最左侧的开头,并使用逻辑循环遍历我们的向量。因此,通过以固定速率移动偏移,我们将在屏幕上创建滚动动作。下图更好地说明了这个概念。
将视频SRAM视为列的伪圆矢量,屏幕的最左边部分用移动偏移标记。
新数据已在旧偏移位置写入SRAM矢量,并且偏移已更新,以便最新输入数据显示在屏幕右侧。
将SRAM作为列的循环缓冲区进行处理可确保我们不必将SRAM数据移位,从而实现快速,平滑的滚动。
VGA约束
我们很早就决定调整VGA控制器会超出我们项目的范围,这使我们的默认屏幕分辨率为640 x 480像素,而25.2 MHz VGA控制时钟。
要查看每次屏幕刷新我们有多少个周期,我们使用了来自http://www.epanorama.net/documents/pc/vga_timing.html的同步信息。根据我们的消息来源,每个水平同步持续96个周期,每个垂直同步持续2行或1600个周期,总共96 * 480 + 1600 = 47,680个周期,在此期间我们可以访问SRAM。
我们更新频谱图中的列并移动偏移的速率决定了滚动的表观速率。所需的滚动速率也取决于窗口在时间和像素上的长度。时钟周期中的读取速率由以下公式确定:
HSL颜色
背景
HSL颜色空间是RGB颜色编码的替代方案。H代表色调,颜色的方面将用 red,yellow或blue等字来描述。它被编码为0到360度的角度,如下图所示。
图片来源:维基百科 - HSL
S代表颜色的饱和度,颜色强度的度量,或感知颜色与颜色灰色的差异程度。L代表亮度,是衡量颜色亮度的标准。低亮度值导致近黑色,高亮度值导致近白色。通过以下双锥图更好地显示HSL颜色空间的组织。
图片来源:维基百科 - HSL
可以使用以下方程组将HSL颜色值转换为RGB值:
我们的HSL色彩空间
在我们的项目中使用HSL色彩空间的主要优点是我们能够编码宽广而平滑的明亮色彩范围,而无需求助于查找表。这是通过使用每个频率的8位幅度作为色调值,并将饱和度值固定为1并将亮度固定为0.5来实现,以显示频谱图。
对于我们的色调和饱和度值,我们计算q值为1,p为0.然后我们将所有公式乘以360,这样我们就可以避免使用分数(从而避免在硬件中进行任何复杂的算术运算) 。最后,我们通过360°的分数255缩放Color结果,允许我们为VGA的每种颜色转换为8位值。得到的方程式每个颜色只需乘以一个固定因子,然后右移一个除法:
实施细节
频率分析: Radix-4 DFT | 硬件权衡 | MATLAB | Verilog | IIR带通滤波器
频谱图显示: 频谱图 | HSL
Radix-4 DFT
每个radix-4 DFT模块被模块化以接收四个输入样本,三个旋转因子和四个输出样本。在每个FFT中进一步优化复数加法和乘法。
每个基数-4蝶形每个样本需要三个复杂的加法,每个蝴蝶总共12个复杂的加法。这可以优化为仅使用8个复杂的添加。由于每个复数加法对应于两个实数加法,这意味着每个蝴蝶有16个实际加法而不是24个加法。
每个基数-4 DFT具有三个旋转因子复数乘法。对于每个复数乘法器,这对应于两个实数加法器和四个实数乘法器。这可以优化为使用五个实数加法器和三个实数乘法。由于乘法器需要比加法器多得多的硬件,因此可以节省大量空间。
所需的总基数为4 DFT的硬件从每个DFT的30个加法器和12个乘法器减少到仅27个加法器和9个乘法器。
硬件权衡
单周期FFT
最初的计划是实现单周期FFT,可以在50 MHz系统时钟的一个时钟周期内计算64点变换。这甚至比音频编解码器可以放出采样的速率(48 kHz)更快。理论上,新的样本将被移入移位寄存器,并且一旦结果通过16个DFT的三个阶段级联,就可以计算64点变换。
但是,硬件要求太多了。由于48个基数为4的DFT并行工作,因此需要288个乘法器(FFT的最后一级不需要旋转因子乘法)。DE2板上使用的Cyclone II FPGA(EP2C35)只有35个嵌入式18位乘法器和足够的硬件,可实现105个软乘法器,总共140个乘法器。单周期实现需要略高于可用逻辑区域的205%,或者换句话说,两个EP2C35 FPGA。当编译器无法将64,000多个逻辑元件装入EP2C35上可用的33,216个逻辑元件时,编译过程失败时验证了这一点。应该注意的是,将来参考可以通过使用更大的FPGA来实现64点FFT,例如EP2C70(400个乘法器,68,416个逻辑元件)。
多周期FFT
虽然仍有一些优化可用于降低硬件要求,但仍决定转换到多周期FFT。
在该配置中,计算是顺序计算而不是并行计算。并行化的数量是可变的,具体取决于并行操作的FFT数量。
一个极端是快速单周期FFT,其中64个样本在一批中通过48个基数-4 DFT级联。另一个极端是慢速多级FFT,其中通过48个批次的序列中的单个基数-4DFT一次处理4个样本。在两个极端之间是混合解决方案,其中多个DFT分阶段地计算样本。一个例子是通过3批中的16个基数-4DFT处理64个样本。
每个阶段需要有限数量的周期来检索样本,计算DFT并存储样本。假设保守估计9个时钟周期(三个时钟周期来检索采样,三个时钟周期来计算DFT,以及三个时钟周期来存储采样),最慢的多级FFT将需要432个周期(48个阶段,9个周期) / stage)计算64点FFT。在50 MHz的系统时钟,这对应于115 kHz的FFT速度。这仍然比音频编解码器为FFT产生输入样本的48 kHz速率快得多。
因此,对于音频速率频谱图,FFT可以在没有任何DFT并行的情况下操作。所需的硬件总数为27个加法器和9个乘法器。权衡是存储,加载和跟踪正在计算的阶段所需的内存使用量。
测序
如果顺序计算FFT,则必须为每个DFT阶段分配正确的样本和旋转因子。这可以通过将输入样本,旋转因子和DFT结果存储到存储器块中来完成。可以创建附加的存储块以存储每个存储块的适当索引,以计算正确的DFT计算序列。
对于64点基数-4 FFT,需要执行48次DFT计算。对于每个DFT计算,需要从RAM中取出四个样本,需要从ROM中取出三个旋转因子,并将四个样本存储回RAM中。四个输入样本,三个旋转因子和四个输出样本的索引可以存储在定序器ROM中。FFT状态机可以通过序列器递增,获取四个样本和三个旋转因子,执行DFT计算,并存储四个结果。重复此过程,直到定序器到达序列ROM中的最后一个条目。在这个阶段,已经计算了所有48个DFT计算,并且可以存储得到的频率数据以供将来使用。
还可以对顺控程序进行优化。最直接的是使用就地FFT算法。这是一种算法,其中输入样本的索引与输出结果中使用的索引相同。因此,输入样本和输出样本可以存储在同一RAM块中,从而减少了所需的总存储量。另外,定序器ROM现在只需要存储一组索引。
MATLAB实现
该实现首先在MATLAB中进行了测试。复数乘法器,radix-4蝶形和音序器都是在MATLAB脚本中创建的,这些脚本近似于未来的硬件实现。将FFT的结果与MATLAB提供的FFT函数进行比较,发现它们具有精确的一一对应关系。
修改了序列发生器的MATLAB脚本,直接从脚本本身自动生成Verilog代码。这允许在FFT的参数改变时非常快速地自动生成Verilog代码。
下面的附录中包含两个MATLAB不同的实现。第一个实现是用于生成64点单周期FFT的实现。第二种实现使用就地FFT算法。这两个参考文献(Tom Wada和Magnus Nilsson)对MATLAB脚本的开发非常有帮助。代码结构的一部分是从学分中列出的MATLAB脚本中复制的。
Verilog实施
Verilog实现直接从MATLAB脚本生成。为了创建单周期FFT,必须适当地命名输入和输出线,以便将正确的值传递到FFT的每个级。对于多周期FFT,必须编写Verilog代码以正确排序样本和旋转因子的检索和存储。
FFT的Verilog代码包含在fft64pt_seq模块中。音频ADC的采样时钟,音频ADC的采样和VGA的握手线都是输入。VGA显示单元可以通过五位地址(32个不同的频率区间)请求特定频率,并以无符号8位结果接收幅度数据。
音频ADC移位寄存器包含64个寄存器,每个寄存器为16位宽。在音频ADC时钟的每个时钟周期,移位寄存器接收最新的ADC采样(16位)并将剩余的采样移位一。可以通过FFT状态机暂停ADC移位寄存器,以便在FFT状态机复制出值时样本不会改变。
ADC移位寄存器的内容可以通过音频采样地址在外部寻址。读取该索引处的ADC样本,并可选地通过窗口函数传递。在将结果发送到FFT状态机之前,窗口函数将ADC样本乘以适当的缩放因子。
FFT状态机使用三个M4K块。第一个是信号RAM,它包含FFT过程中使用的64个数据样本。第二个是旋转因子ROM,它包含用于每个DFT阶段的旋转因子。第三个是程序序列ROM,它包含每个DFT计算的前两个M4K块的索引。
信号RAM是双端口RAM,以最大化数据带宽。有两个输入,每个输入36位。每个输入包含两个带符号的18位值,表示每个复数的实部和虚部。相同的格式适用于信号RAM输出。
有一系列多路复用器可控制数据流入和流出信号RAM。RAM可以一次存储或加载两个复数。信号RAM的输入来自ADC移位寄存器或DFT输出。信号RAM的输出进入DFT输入或VGA显示。
FFT状态机编排程序定序器,信号RAM,旋转ROM,ADC移位寄存器和VGA控制块之间的复杂交互。一般来说,FFT状态机可以分为四种状态:保持,加载,存储和采样。
在保持状态期间,VGA控制器可以停止FFT,以便VGA控制器可以访问信号RAM。如果没有停止FFT,则状态机检查是否需要获取新样本(样本状态)。如果样本已写入信号RAM,则FFT跳转到负载状态。DFT序列计数器递增,因此程序定序器可以加载DFT计算所需的索引。一次从信号RAM中检索两个样本的信号样本。从旋转ROM中检索旋转因子。实际的DFT计算发生在组合逻辑中,因此转换后的值在单个周期内就绪。然后将信号样本存储回信号RAM。递增DFT计数器并重复整个过程,直到计算出所有48个DFT。
实际的DFT在radix4dft中模块化。复数乘数在optcomplexmult中模块化。每个使用的优化都记录在Verilog文件的注释中。
带通IIR滤波器
带通滤波器是四阶IIR椭圆滤波器。滤波器模块来自ECE 576课程页面,完全模块化,使用带符号的18位定点表示法。MATLAB文件中还有其他代码可生成滤波器抽头权重。修改这些MATLAB脚本以生成32个带通滤波器,这些滤波器可以在采样频谱上线性或对数地间隔开。此外,MATLAB脚本被修改为自动执行必要的缩放系数。每个滤波器使用一个18位乘法器。完整的带通滤波器组使用32个嵌入式18位乘法器。
谱图
实现频谱图的第一步是控制读取频率输入的速率并将其复制到显示SRAM中。我们选择使用以VGA CTRL CLK速率运行的32位累加器,以确定何时采样和更新。只要累加器等于或大于值(CLK * T / X),我们就会在下次机会读取频率并从累加器中减去(CLK * T / X)。在我们的最后一次迭代中,时间窗口可以使用开关2-0进行选择,开关2-0被硬连线到表示2秒到9秒的窗口的常数。采样常数是硬连线的,以避免使用乘法器单元。
接下来,我们需要一个状态机来断言对包含频率幅度的寄存器的控制,阻止它们被覆盖,并将它们读入缓冲区。在垂直同步期间,读取该缓冲区并将其复制到SRAM中,在每列复制后更新指针偏移值。在垂直同步期间,我们有足够多的周期将每个32个频率的6个样本复制到SRAM中。
该频率复制状态机如下图所示:
VGA帧状态机 通过垂直同步复位。
在我们创建了状态机之后,我们需要将逻辑添加到VGA的像素爆破组件中,该组件将根据水平偏移和频率分级重定向正在读取的SRAM地址。我们选择使用尺寸为600 x 256像素的光谱图。我们需要显示32个不同的频段,这意味着每个频段的高度为8像素。我们不是在SRAM中将每个频率的幅度写入8次,而是忽略了频谱图显示中每个Y坐标的低3位。
我们决定显示每个视频帧存储到视频内存的最后频率幅度的条形图,类似于音频均衡器上常见的频率。我们实现了这一点,而无需对视频内存执行任何额外的写操作。相反,我们定义了一个512 x 128像素的区域(32条最大高度128像素,每条16像素宽)专用于这些条形图,并使用存储在频率缓冲区最后一个条目中的大小来确定每个酒吧的高度。
在像素爆炸期间基于像素的屏幕高度重定向SRAM。
使用缓冲区中存储的频率幅度的高7位设置每个条的高度,如果被寻址的像素位于条形图上方,我们再次使用地址重定向and,因此黑色,我们通常对SRAM进行寻址,如果像素是条形图的一部分,我们将写入写入视频存储器的频谱图部分的最后一列的相应段。因此,我们在需要写入SRAM的数据方面免费实现额外的显示功能。
测试
首先,我们通过在复位时在SRAM中的黑色背景上绘制白色对角线来测试我们的滚动概念,并添加逻辑以调整每个垂直同步上的水平偏移,并通过偏移量调整VGA控制器寻址的存储位置。我们快速而肮脏的测试证明了这个概念可以工作并生成一个非常平滑的滚动,几乎不需要逻辑方式。
其次,我们通过创建一个随机位生成器并不断将其输出的8位块复制到一系列32个寄存器中来测试我们将频率信息放入显示存储器的能力。如果断言 hold 线,这些寄存器将保持其值,并且可由我们的显示状态机使用大型32对1多路复用器进行寻址和读取。我们的测试表明,我们可以很好地读取无意义的输入流,但也在我们的显示中发现了一个问题。最初,读取被直接写入SRAM,导致频谱图在帧中更新。这会以水平线向上的形式创建屏幕瑕疵,并且在视觉上分散注意力。为了解决这个问题,我们创建了频率幅度缓冲区,并且只在垂直同步时复制到SRAM中。这导致了平稳的表现,
接下来,我们实现了条形图功能,并用固定级别替换了我们的随机输入。这揭示了显示重定向逻辑中的一些寻址错误,例如从错误输入读取的频率仓。这些错误得到纠正,显示再次起作用。
我们的显示器组件的最终版本以平滑的60 Hz帧速率运行,并且可以在2到9秒的可选时间窗口中在频谱图中显示32个频率幅度,并附带最近输入的条形图。
HSL实施
HSL方程使用组合逻辑和寄存器实现为SRAM数据和VGA颜色输入之间的阶段。转换在SRAM数据和VGA颜色输入之间增加了1个延迟周期,因此我们必须修改VGA控制器,以便在一个周期之前对SRAM进行补偿。
测试
我们通过简单地在复位时在SRAM中写入0到255的色调值的线性扫描来测试我们的HSL色彩空间。得到的图像是从红色到绿色到蓝色的平滑过渡 但是,红色对应于SRAM中的0,因此我们必须添加一个简单的减法来反转我们的颜色范围的方向,从而将蓝色置于“低端”在 high 结束时是红色的。
最后,我们必须添加逻辑,以便在未显示频率信息的区域中正确地将黑色绘制到屏幕上。由此产生的显示器具有令人愉快和鲜艳的色彩,使其更具吸引力。