信号系统之快速傅里叶变换

1 使用复数DFT的实数DFT

本文的主题,如何使用 FFT 计算真正的 DFT?

由于 FFT 是一种用于计算复数 DFT 的算法,因此了解如何将实数 DFT 数据输入和输出复数 DFT 格式非常重要。图 12-1 比较了实数 DFT 和复数 DFT 存储数据的方式。实数 DFT 将一个 N 点时域信号转换为两个 N/2+1 点频域信号。​频域中的两个信号称为实部和虚部,分别保持余弦波和正弦波的幅度。

相比之下,复数DFT将两个N点时域信号转换为两个N点频域信号。两个时域信号称为实部和虚部,就像频域信号一样。

假设有一个 N 点信号,并且需要通过复数 DFT 计算实际 DFT。首先,将 N 点信号移动到复数 DFT 时域的实部,然后将虚部中的所有样本设置为零。计算复数 DFT 后,在频域中产生一个实数和一个虚数信号,每个信号由 N 个点组成。这些信号的样本 0 到 N/2 对应于真实 DFT 的频谱。

当包含负频率时,DFT的频域是周期性的。单一时期的选择是任意的;它可以在 -1.0 和 0、-0.5 和 0.5、0 和 1.0 之间选择,也可以在任何其他以采样率为基准的单位间隔之间进行选择。复数 DFT 的频谱包括 0 到 1.0 排列中的负频率。换言之,一个完整的周期从样本 0 延伸到样本 N-1,相当于采样率的 0 到 1.0 倍。正频率介于样本 0 和 N/2 之间,对应于 0 到 0.5。其他样本,介于 N/2+1 和 N-1 之间,包含负频率值(通常被忽略)。

使用复数逆 DFT 计算真正的逆 DFT 稍微困难一些。这是因为需要确保以正确的格式加载负频。复数 DFT 中的点 0 到 N/2 与实数 DFT 中的点相同,无论是实部还是虚部。对于实部,点 N/2+1 与点 N/2-1 相同,点 N/2+2 与点 N/2-2 相同,依此类推。这继续表明 N-1 点与点 1 相同。虚部使用相同的基本图案,只是符号发生了变化。也就是说,点 N/2+1 是点 N/2-1 的负数,点 N/2+2 是点 N/2-2 的负数,依此类推。请注意,样本 0 和 N/2 在此复制方案中没有匹配点。在实践中,将真实 DFT 的频谱加载到复数 DFT 阵列的样本 0 到 N/2 中,然后使用子程序在样本 N/2+1 和 N-1 之间生成负频率。表 12-1 显示了这样的程序。为了检查是否存在适当的对称性,在进行逆 FFT 后,查看时域的虚部。如果一切都正确,它将包含所有零(除了百万分之几的噪声,使用单精度计算)。

2 FFT 的工作原理

FFT 是一种复杂的算法,其细节通常留给专门研究此类事物的人。本节介绍FFT的一般操作,但忽略了一个关键问题:复数的使用。

在复数记数法中,时域和频域各包含一个由 N 个复点组成的信号。这些复点中的每一个都由两个数字组成,即实部和虚部。例如,当谈论复样本 X[42] 时,它指的是 ReX[42] 和 ImX[42] 的组合。换句话说,每个复变量包含两个数字。当两个复变量相乘时,必须将四个单独的分量组合在一起以形成乘积的两个分量。

FFT 的工作原理:

  • 将 N 点时域信号分解为 N 个时域信号,每个时域信号由一个点组成。
  • 第二步是计算与这些N个时域信号对应的N个频谱。
  • 最后,将 N 频谱合成为单个频谱。

图 12-2 显示了 FFT 中使用的时域分解示例。在此示例中,一个 16 点信号通过 4 个独立的阶段。

  • 第一阶段将 16 点信号分成两个信号,每个信号由 8 个点组成。
  • 第二阶段将数据分解为4个点的4个信号。这种模式一直持续到有 N 个信号由单个点组成。每次将信号一分为二时,都会使用隔行分解,即将信号分成偶数和奇数样本。理解这一点的最好方法是检查图 12-2。这种分解需要 L o g 2 N Log_2N Log2N 级,即 16 点信号( 2 4 2^4 24)需要 4 级,512 点信号( 2 7 2^7 27)需要 7 级,4096 点信号( 2 1 2 2^12 212)需要 12 级,以此类推。

分解无非是信号中样本的重新排序。图 12-3 显示了所需的重排模式:

  • 在左侧,列出了原始信号的样本编号及其二进制等效物。
  • 在右侧,列出了重新排列的样本编号,以及它们的二进制等价物。

重要的想法是二进制数是彼此的反转。例如,样本3(0011)与样本12(1100)交换。同样,样本14(1110)与样本7(0111)交换,依此类推。FFT时域分解通常通过比特反转排序算法进行。这涉及通过以二进制方式计数,将位从左翻转为右翻转(例如在图 12-3 中最右边的列中)来重新排列 N 个时域样本的顺序。

FFT 算法的下一步是找到 1 点时域信号的频谱。没有比这更容易的了;1点信号的频谱等于自身。这意味着执行此步骤不需要任何内容。现在 1 点信号中的每一个都是频谱,而不是时域信号。

FFT 的最后一步是以与时域分解发生的完全相反的顺序组合 N 频谱。这就是算法变得混乱的地方。不幸的是,位反转快捷方式不适用,必须一次返回一个阶段。第一阶段,将16个频谱(每个1点)合成为8个频谱(每个点2点)。在第二阶段,将 8 个频谱(每个 2 点)合成为 4 个频谱(每个 4 点),依此类推。最后阶段产生 FFT 的输出,这是一个 16 点频谱。

图 12-4 显示了如何将两个频谱(每个频谱由 4 个点组成)组合成一个由 8 个点组成的单个频谱。这种合成必须撤消在时域中完成的隔行分解。换言之,频域操作必须对应于通过隔行扫描组合两个 4 点信号的时域过程。考虑两个时域信号,abcd 和 efgh。8 点时域信号可以通过两个步骤形成:

  • 用零稀释每个 4 点信号,使其成为8点信号,然后将信号加在一起。也就是说,abcd 变为 a0b0c0d0,efgh 变为 0e0f0g0h。
  • 将这两个 8 点信号相加会产生 aebfcgdh。如图12-4所示,用零稀释时域对应于频谱的重复。

因此,在FFT中,通过复制频谱,然后将复制的频谱相加,在FFT中进行组合。

为了在添加时匹配,两个时域信号以略有不同的方式用零稀释。在一个信号中,奇数点为零,而在另一个信号中,偶数点为零。换言之,其中一个时域信号(图12-4中的0e0f0g0h)被一个样本向右移动。这个时域偏移对应于将频谱乘以正弦曲线。时域中的位移等价于使用位移的 delta 函数对信号进行卷积。这会将信号的频谱乘以移位增量函数的频谱。偏移 delta 函数的谱是正弦曲线(见图 11-2)。

图 12-5 显示了将两个 4 点光谱组合成一个 8 点光谱的流程图。为了进一步减少这种情况,请注意,图 12-5 是由图 12-6 中的基本模式一遍又一遍地重复形成的。

这个简单的流程图因其有翅膀的外观而被称为蝴蝶。蝴蝶是FFT的基本计算元件,将两个复点转换为另外两个复点。

图 12-7 显示了整个 FFT 的结构。时域分解是通过比特反转排序算法完成的。将分解后的数据转换为频域不涉及任何内容,因此不会出现在图中。

频域合成需要三个环路。外部循环贯穿 L o g 2 N Log_2N Log2N 阶段(即图 12-2 中的每个级别,从底部开始并移动到顶部)。中间环路穿过正在处理的阶段中的每个单独的频谱(即图 12-2 中任何一个水平上的每个框)。最里面的环路使用蝶形来计算每个频谱中的点(即,循环遍历图 12-2 中任何一个框内的样本)。图 12-7 中的架空框确定循环的开始和结束索引,以及计算蝴蝶所需的正弦曲线。

3 FFT 程序

可以通过将时域信号与正弦波和余弦波相关联来计算真正的DFT。表 12-2 显示了用相同方法计算复数 DFT 的程序。在同类比较中,这是 FFT 改进的程序。

表 12-3 和 12-4 显示了两个不同的 FFT 程序,一个在 FORTRAN 中,一个在 BASIC 中。首先,将查看表 12-4 中的 BASIC 例程。此子例程产生的输出与表 12-2 中的关联技术完全相同,只是它的速度要快得多。图 12-7 中的框图可用于识别该程序的不同部分。数据被传递到数组中的这个 FFT 子例程:REX[] 和 IMX[],每个子例程从样本 0 到 N-1 运行。从子例程返回后,REX[] 和 IMX[] 将被频域数据覆盖。这是 FFT 高度优化的另一种方式;输入、中间存储和输出使用相同的数组。这种对存储器的有效利用对于设计快速硬件来计算FFT非常重要。

虽然所有 FFT 程序都产生相同的数值结果,但需要注意编程中的细微变化。表 12-3 中列出的 FORTRAN 程序说明了重要的差异。该程序使用一种称为频率抽取(decimation in frequency)的算法,而前面描述的算法称为时间抽取(decimation in time)。在频率抽取算法中,位反转排序是在三个嵌套循环之后完成的。还有一些 FFT 例程可以完全消除位反转排序。这些变化都没有显著提高 FFT 的性能。

FFT 算法之间的重要区别在于数据如何输入和输出子程序。在 BASIC 程序中,数据进入和离开数组 REX[] 和 IMX[] 中的子程序,样本从索引 0 到 N-1。在FORTRAN程序中,数据在复数组 X() 中传递,样本从1到N。由于这是一个复变量数组,因此 X() 中的每个样本都由两个数字组成,一个实部和一个虚部。DFT 的长度也必须传递给这些子例程。在 BASIC 程序中,变量 N% 用于此目的。相比之下,FORTRAN 程序使用变量 M,该变量定义为等于 L o g 2 N Log_2N Log2N。例如,M 将是 8 表示 256 点 DFT,12 表示 4096 点 DFT,以此类推。关键是,编写 FFT 子例程的程序员有许多与主机程序交互的选项。从 1 到 N 运行的数组(例如在 FORTRAN 程序中)尤其令人恼火。大多数 DSP 文献(包括本书)都解释了假设阵列从样本 0 到 N-1 运行的算法。例如,如果阵列从 1 到 N,则频域中的对称性约为点 1 和 N/2 + 1,而不是点 0 和 N/2。

使用复数 DFT 来计算实际 DFT 还有另一个有趣的优势。复数DFT在时域和频域之间比实际DFT更对称。也就是说,二元性更强。除其他外,这意味着反向 DFT 与正向 DFT 几乎相同。事实上,计算反向 FFT 的最简单方法是计算 Forward FFT,然后调整数据。表 12-5 显示了以这种方式计算逆 FFT 的子例程。

假设将这些 FFT 算法之一复制到计算机程序中并启动它运行。怎么知道它是否正常运行?调试通常使用两种技巧:

  • 首先,从一些任意时域信号开始,例如来自随机数生成器的信号,然后通过FFT运行它。接下来,通过反向FFT运行生成的频谱,并将结果与原始信号进行比较。它们应该是相同的,除了舍入噪声(单个精度为百万分之几)。
  • 正确操作的第二个测试是信号是否具有正确的对称性。当时域信号的虚部由所有零组成时(正常情况),如前所述,复数DFT的频域将在样本0和N/2周围对称。同样,当频域中存在这种正确的对称性时,逆 DFT 将产生一个时域,该时域的假想部分由所有零(加上舍入噪声)组成。这些调试技术对于使用 FFT 至关重要;熟悉他们。

4 速度和精度比较

当通过相关性计算 DFT 时(如表 12-2 所示),程序使用两个嵌套循环,每个循环运行 N 个点。这意味着操作总数与 N 乘以 N 成正比。因此,完成该计划的时间由以下因素给出:

其中 N 是 DFT 中的点数, k D F T k_{DFT} kDFT 是比例常数。如果在嵌套循环中计算正弦和余弦值,则 k D F T k_{DFT} kDFT 等于大约 25 微秒,在 100 MHz 的奔腾上。如果预先计算正弦和余弦值并将它们存储在查找表中,则 k D F T k_{DFT} kDFT 将下降到大约 7 微秒。例如,一个 1024 点的 DFT 大约需要 25 秒,或者每个点将近 25 毫秒。

使用相同的策略,可以推导出 FFT 的执行时间。位反转所需的时间可以忽略不计。在每个 L o g 2 N Log_2N Log2N 阶段中,都有 N/2 个蝴蝶计算。这意味着程序的执行时间近似为:

在 100 MHz Pentium 系统上, k F F T k_{FFT} kFFT 的值约为 10 微秒。一个 1024 点 FFT 大约需要 70 毫秒才能执行,即每个点 70 微秒。这比通过相关性计算的 DFT 快 300 多倍!

N L o g 2 N NLog_2N NLog2N 不仅小于 N,而且随着 N 2 N^2 N2 变大,它的增长速度要慢得多。例如,32 点 FFT 比相关方法快约 10 倍。然而,4096 点 FFT 的速度要快一千倍。对于较小的 N 值(例如,32 到 128),FFT 很重要。对于较大的 N 值(1024 及以上),FFT 绝对至关重要。图 12-8 以图形形式比较了两种算法的执行时间。

除了原始速度之外,FFT 还有另一个优势。FFT 的计算更精确,因为计算次数越少,舍入误差就越小。这可以通过获取任意信号的 FFT,然后通过反向 FFT 运行频谱来证明。这将重建原始时域信号,但从计算中增加了舍入噪声。通过计算两个信号之间差值的标准偏差,可以得到表征该噪声的单个数字。为了进行比较,可以使用通过相关性计算的 DFT 和相应的逆 DFT 来重复相同的过程。FFT的舍入噪声与DFT的相关性如何比较?请看图 12-9 中的亲眼目睹。

5 速度进一步提高

有几种技术可以使 FFT 更快;但改进只有大约 20-40%。在其中一种方法中,当每个信号仅由四个点组成时,时域分解提前两个阶段停止。使用高度优化的代码直接跳转到频域,而不是计算最后两个阶段,使用四点正弦波和余弦波的简单性。

另一种流行的算法消除了与时域的虚部为零和频谱对称相关的浪费计算。换言之,修改 FFT 以计算实际 DFT,而不是复数 DFT。这些算法称为实数 FFT 和实数逆 FFT(或类似名称)。预计它们比传统的 FFT 例程快约 30%。表 12-6 和 12-7 显示了这些算法的程序。

使用真正的FFT有两个小缺点:

  • 首先,代码的长度大约是原来的两倍。
  • 其次,调试这些程序稍微困难一些,因为不能使用对称性来检查是否正确运行。这些算法强制时域的虚部为零,频域具有左右对称性。对于调试,请检查这些程序是否产生与传统 FFT 算法相同的输出。

图 12-10 和 12-11 说明了实际 FFT 的工作原理。在图12-10中,(a)和(b)显示了一个时域信号,该信号由实部中的脉冲和虚部中的所有零组成。图(c)和(d)显示了相应的频谱。频域的实部在样本 0 和样本 N/2 周围具有偶数对称性,而虚部在这些相同点周围具有奇数对称性。

现在考虑图 12-11,其中脉冲位于时域的虚部,实部全为零。频域中的对称性是相反的;实数部分是奇数,而虚数部分是偶数。

如果时域的两个部分都有信号怎么办? 通过加性,频域是两个频谱的总和。关键要素是:由这两种对称性组成的频谱可以完美地分离成两个分量信号。其中一个信号放置在时域的实部,另一个信号放置在虚部。在计算复数DFT(当然是通过FFT)之后,使用偶数/奇数分解分离光谱。当需要通过两个或多个信号通过FFT时,该技术可将执行时间缩短约40%。

下一步是修改算法以更快地计算单个 DFT。通过使用隔行分解将输入信号分成两半。N/2 个偶数点被放置在时域信号的实部,而 N/2 个奇点被置于虚部。然后计算 N/2 点 FFT,所需时间约为 N 点 FFT 的一半。然后通过偶数/奇数分解分离产生的频域,从而产生两个交错时域信号的频谱。然后将这两个频谱组合成一个频谱,就像在FFT的最后一个合成阶段一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2821954.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

LNMP架构介绍及配置--部署Discuz社区论坛与wordpress博客

一、LNMP架构定义 1、LNMP定义 LNMP(Linux Nginx Mysql Php)是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写;Linux系统下NginxMySQLPHP这种网站服务器架构。 Linux是一类Unix计算机操作系统的统称,是目…

线性规划在多种问题形式下的应用

线性规划的用处非常的广泛,这主要是因为很多类型的问题是可以通过转化的方式转化为线性规划的问题。例如需要再图论中寻找起始点到给定的点的最短路径问题: 添加图片注释,不超过 140 字(可选) 假设要计算从节点0到节点4的最短路径,用变量d1到d4来表示节点0到节点1,2,3,…

HTML5+CSS3+JS小实例:右键菜单

实例:右键菜单 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><met…

插混、油混、增程式、轻混、强混,啥区别

这里写自定义目录标题 随着我国新能源汽车的大力推进&#xff0c;电车可以说是世界未来的主流&#xff0c;只不过现在是处在一个过渡时代 这是个好时代&#xff0c;因为我们见证并体验着历史过渡的细节 这是个不好的时代&#xff0c;因为我们可能只是未来新新人类的试验品 帮他…

javascript中的class基础入门(1)

javascript中的class start 最近在学习&#xff1a;cocos &#xff0c;准备自己制作小游戏。过程中遇到不少疑问&#xff0c;我计划将这些疑问写成一个系列博客&#xff0c;用以记录。这篇文章来了解 class 1. 前言 1. 前言 本文对应版本 Cocos Creator 3.8。Cocos Creato…

mysql-Synch-clickhouse

Synch GitHub - long2ice/synch: Sync data from the other DB to ClickHouse(cluster) 环境&#xff1a; mysql5.7 redis > 5.0 clickhouse21.2 postgresql python3 binlog_formatrow XREAD default pg_config synch 1&#xff1a;安装clickhouse rpm下载地址&…

今日arXiv最热大模型论文:点击即可播放!港中文发布大模型写歌神器!

一首歌&#xff0c;包含作词作曲两个部分。擅长作词or作曲就已经很牛了。比如方文山是周杰伦的御用作词人&#xff0c;而周杰伦写过很多耳熟能详的曲子。而兼具作词作曲才华的全能创作人却是难得一见。 最近港中文发布了一款歌曲创作大模型SongComposer&#xff0c;作词作曲都…

DiskMirror-spring-boot-starter 技术|

DiskMirror-spring-boot-starter 技术 diskMirror 实现了 SpringBoot 的 starter 能够集成到 SpringBoot 中。 DiskMirror 的 starter&#xff0c;通过引入此类&#xff0c;可以直接实现 diskMirror 在 SpringBoot 中的自动配置&#xff0c;接下来我们将使用案例逐步的演示 d…

飞腾平台编译安装openGauss数据库

1. 环境检查 1.1 检查OS版本 openGauss支持的操作系统&#xff1a; CentOS 7.6&#xff08;x86_64 架构&#xff09;openEuler-20.03-LTS&#xff08;aarch64 架构&#xff09;openEuler-20.03-LTS&#xff08;x86_64架构&#xff09;Kylin-V10&#xff08;aarch64 架构&…

作业1-224——P1015 [NOIP1999 普及组] 回文数

题目描述 思路 首先此题为一道高精度题&#xff0c;然后本题按照题目意思模拟即可。我们可以开两个数组来记录高精度数字&#xff0c;这样方便我们处理。判断“该数组是否回文”、“c翻转存入d再做cd”可以写成两个单独的函数。然后主程序组织一下他们即可。注意好退出循环的…

String类的使用

String常用的构造方法 String的源码 内部是一个数组和hash值&#xff0c;涉及到常量池后续补充&#xff08;常量池&#xff1a;存储相同的字符时只会存储一租&#xff09; String的比较 equals()与&#xff1a;String里面为我们提供了许多方法&#xff0c;可直接调用&#xf…

electron 项目环境变量使用注意 public

问题 最近项目中&#xff0c;electron需要调用唤醒本地的另一个客户端程序&#xff0c;但是这个客户端程序报错了。sqlite3 报out of memory. apiSHGetFolderPathW 获取CSIDL_COMMON_DOCUMENTS报 1008&#xff0c;试图引用不存在的令牌。 排查 一看到这个&#xff0c;首先想…

苍穹外卖Day03——解决总结3中存在的问题

解决Day03中存在的问题 1. ResponseBody 与 RequestBody2. RequestParam 与 PathVariable3. 字段填充技术&#xff08;注解、AOP、反射&#xff09;3.1. AOP3.2. 注解3.3. 反射3.5 字段填充在项目应用 4. 阿里云云存储OOS 1. ResponseBody 与 RequestBody ResponseBody&…

varFormatter 数据格式化库 以性能优先的 快速的 内存对象格式转换

varFormatter 数据格式化 技术 开源技术栏 对象/变量格式化工具库&#xff0c;其支持将一个对象进行按照 JSON XML HTML 等格式进行转换&#xff0c;并获取到结果字符串&#xff01; 目录 文章目录 varFormatter 数据格式化 技术目录介绍获取方式 使用实例格式化组件的基本使…

WIN10 无密码自动登录

1、家里重装了一下WIN10系统&#xff0c;第一次登陆居然用了微软网站账号&#xff0c;结果密码忘记了&#xff0c;后面只能用PIN码登陆系统。 2、需要登录微软的网站修改密码&#xff1a; Microsoft account | Sign In or Create Your Account Today – Microsoft 3、在运行…

【C语言】动态内存管理常用函数

前言 我们在之前学习的数组开辟的空间是固定不变的&#xff0c;有时候我们需要的空间⼤⼩在程序运⾏的时候才能知道~ c语言中的动态内存开辟&#xff0c;让程序员⾃⼰可以根据实际需求申请和释放相应空间&#xff0c;这使得空间的开辟变得灵活了许多。 欢迎关注个人主页&#x…

数据库原理及应用 第三章:关系数据模型

文章目录 三、关系数据模型3.1.1关系模型概述3.1.2候选键和外键3.2关系模型的完整性 三、关系数据模型 3.1.1关系模型概述 3.1.2候选键和外键 3.2关系模型的完整性

写作软件,批量写作文章的软件

在信息爆炸的时代&#xff0c;写作软件成为许多人提高效率、优化内容的利器。本文将介绍6款不同的写作软件&#xff0c;以及知名的147GPT生成工具和文心一言AI生成软件&#xff0c;它们不仅可以帮助用户快速生成原创文章&#xff0c;还支持全自动SEO优化&#xff0c;提升文章在…

wy的leetcode刷题记录_Day79

wy的leetcode刷题记录_Day79 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2024-3-1 前言 目录 wy的leetcode刷题记录_Day79声明前言2369. 检查数组是否存在有效划分题目介绍思路代码收获 61. 旋转链表题目介绍思路代码收获 82. 删除排…

【Vue】npm run build 打包报错:请在[.env.local]中填入key后方可使用...

报错如下 根目录添加 .env.local 文件 .env.local &#xff1a;本地运行下的配置文件 配置&#xff1a;VUE_GITHUB_USER_NAME 及 VUE_APP_SECRET_KEY 原因