快速傅里叶变换(FFT)算法学习
前言
人生如逆旅,我亦是行人。
一、介绍
算法的世界多么广大,我们可以将算法大致分为两类:
第一类是较为有用的算法:比如一些经典的图算法,像 DFS 和 BFS(深度 / 广度优先算法),这些算法应用在很多方面,他们非常高效,
第二类算法是那些极具美感的算法:例如当我们第一次看到汉诺塔的递归实现算法时的状态,你肯定会觉得这个算法贼牛逼,甚至会被它的美感所震撼到,但这些算法或许并没有那么有用或者高效,不过我们还是会研究它,就像没事干了我们还是会看小说;
这些伟大而精妙的算法会激发我们的灵感,促使我们发散性思考,下面介绍一种同时属于以上两类的算法:快速傅里叶变换(FFT
)。
FFT
算法毫无疑问是上个世纪发明的最伟大的算法之一。很多我们现代生活所依赖的科技,比如无线通讯和 GPS ,以至于任何和信号处理有关的算法,都依赖于 FFT
的深刻洞见。
人们常常不能感知 FFT 的美感,因为它常常有很长很长的前置知识要求, 比如离散傅里叶变换、时域/频域转换、甚至更多。
yysy(有一说一),想要真正搞清 FFT 的应用,你也不得不把这些前置要求都学好。
快速傅里叶变换 (
fast Fourier transform
), 即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,简称FFT
。
二、学习
- 简单的问题:给定两个多项式,计算二者的乘积。
- 我们的任务就是设计高效的算法解决这个问题。
- 数学上,这个问题可以直接通过重复使用乘法分配律解决。
但是在计算机中,首先需要解决的问题是,如何存储一个多项式?
显然,最自然的做法就是储存多项式的系数。我们只需要把系数映射到一个数组中。
系数应该按如下图所示的顺序储存。
因为这样一来数组的第 k 个数字正好对应多项式的 k 阶项系数。
这种表示方法为多项式的系数表示方法。
一般情况下,给定两个 d
阶多项式,二者乘积应为 2d
阶多项式。
并且这一算法,如果用 naive 的乘法分配律来算,时间复杂度为 O(d ^ 2)
。因为多项式 A 的每一项都会跟多项式 B 的每一项相乘。
如何改进这个算法?
例子
我们以最简单的多项式,即一阶多项式/线性函数为例。
我们可以用两个系数来表示线性函数,即截距(0阶系数)和斜率(1阶系数)(注:一对系数一对一决定了唯一的一条直线),还有没有别的直线的表示也可以唯一确定一个直线呢?
表示其实很多,我们这里使用直线的两点表示。
美丽的几何学告诉我们:两点确定一条直线。
事实上:高阶多项式也有类似的性质。 (即:任意 d 阶多项式都由 d+1 个点唯一确定的)
例如下图中的三个点确定了左边这个二次函数:
如果图中有四个点,那么我们就能确定左边这个唯一的三次函数:
接下来证明一下这个结论:
- 假设我们有
p(x)
这个d
阶多项式,通过了给定的d+1
个点,我们需要证明:系数是唯一。 - 因此,我们将这 d+1 个点带入多项式的方程,得到 d+1 个方程。线性方程组当然可以写作 矩阵-向量 表示。
- 矩阵
M
可逆,只要这些点 x_0、… 、x_d
不重复(即两两都不同(下面为 范德蒙德矩阵)),只需证明M
的行列式不为零(范德蒙德行列式)
从而我们知道系数p_0、… 、p_d
是被d+1
个点唯一确定的,从而多项式也是唯一的。
我们现在有两种表示多项式的方法:
- 第一种是系数表示法;
- 第二种是
d+1
个点表示法,称为值表示法;(利用值表示法,多项式乘法变得不能再简单了)
回到之前的问题
乘出来的多项式 C(x)
必然为 4
阶,所以需要 5
个点表示。我们现在只需要挑出五个点并计算已有的两个多项式的值,然后把对应每个点的两个值相乘,得到 C
在每个点的函数值。
根据我们前面的学习,五个点可以确定唯一的多项式,
这个多项式的系数表示我们也算出来了,利用值表示法,我们计算多项式乘法的时间一下子从 O(d^2)缩短到了 O(d)。
接下来开始快速的多项式乘法算法了。
问:
- 给定两个系数表示的 d 阶多项式,我们已经知道了值表示法计算多项式乘法更快,所以我们可以先计算两个多项式在 2d + 1 个点上的值,然后将函数值一对对地乘起来,从而得到乘出来的多项式的值表示,最后,将值表示转换回系数表示。
- 主要的方法我们大致已经清楚,现在的问题在于还有些步骤我们没搞清楚,
- 事实上我们缺的就是:如何将系数转换成值表示,以及反过来,如何将值表示转换成系数?
- 这一过程,实际上就是
FFT
重要之处。
四、求值(evaluation)
让我们先关注一个方向:从系数表示到值表示。这个问题称为求值(evaluation)。
给定 d 阶多项式和 n 个点,我们想计算多项式在这 n 个点上的值(n >= d+1)
- 我们可以采取粗暴的方式:直接在 x 轴上挑取 n 个点,一个一个计算函数值,但是如果这样计算的话,将会变得十分麻烦。 即每个点的计算都是 O(d),加起来还是 O(nd) >= O(d^2)。这样问题又变得像最初那样复杂,现在的问题是能不能整点更快的?
- 将问题简化一下:考虑一个简单的多项式,比如:P(x) = x ^ 2,在 n=8 个点进行求值。
- 那么问题又来了,我们选那八个点更具有代表性呢?
- 有没有这样的一对点:当你知道一个点的函数值时,另一个点的也可以立刻知道?
- 答案是:互为相反数的数对。(前提是:函数 P 是一个偶函数)
- 如果是 P(x) = x^3 咋办,?
- 事实上这个技巧依旧是对的,不过我们要在 -x 的函数值前面加个负号,
- 所以在这两个偶/奇函数的情形中,我们只需要计算一半数量的点就好了,因为剩下一半从奇偶性中就可以的得到了。
再来看看奇偶这个点子对一般的多项式还适不适用,将多项式分成奇/偶函数两个部分,把奇函数部分的 x 提出来一个,那么两个括号里都是两个偶多项式函数。
这样的分解使得我们对于一对相反数计算函数值时,只需要计算其中一个,同时我们可以把两部分都看作 x^2 的函数,你可以看到两个子函数的阶数都降到了 2,比原来的 5 阶不知道高到哪去了。
- 推广这一想法,如果我们有一个 n-1 阶多项式,我们想计算它在 n 个点的函数值,我们可以将多项式分为 奇 / 偶两部分,每部分都只有 n/2 - 1 阶
- 对于这两个只有一半阶的多项式,我们怎么计算他们在对应点的值呢? 这又是一个求值问题,不过这次我们需要计算我们所给的点的平方的函数值。因为我们一开始取了一对对相反数,所以平方之后正好只剩 n/2 个点了,有没有一点像递归算法。
- 总结:计算多项式 P 在 n 个点上的值,这 n 个点是一对对的相反数。我们把多项式分成(如上所述)的两个部分,从而我们有两个阶为 n/2 - 1 的多项式,每个多项式也只需要求 n/2 个点的值。我们只需要递归地求这两个小多项式的值,利用下方这两个公式带回去,就可以得到原多项式的 n 个的值。最后我们就得到了原多项式的值的表达。
如果上述的一切都行得通,那么我们的时间复杂度仅为 O(nlogn)
,因为两个子问题都是原问题规模的一半,而且我们只需要线性时间来计算原多项式的值。
- (一个问题)在递归步骤:我们假设了每个多项式我们都使用相反数来对其进行求值。注意对子问题而言,每个求值点都是平方数,所以都是正的,递归不成立。
- 如何将新的求值点也搞成相反数对?
唯一的方法:就是将这些点都取成复数。这也正是 FFT 算法最奇思妙想的地方。
我们需要专门挑一些复数,使得它们平方之后,依旧是正负成对出现的。
现在又有一个问题来了:该怎么取这些复数呢?
- 我们可以通过一个逆向工程来得到答案。
快速傅里叶变换(FFT)算法学习相关推荐
- OpenCV快速傅里叶变换(FFT)用于图像和视讯流的模糊检测
OpenCV快速傅里叶变换(FFT)用于图像和视频流的模糊检测 翻译自[OpenCV Fast Fourier Transform (FFT) for blur detection in images ...
- 基于python的快速傅里叶变换FFT(二)
基于python的快速傅里叶变换FFT(二) 本文在上一篇博客的基础上进一步探究正弦函数及其FFT变换. 知识点 FFT变换,其实就是快速离散傅里叶变换,傅立叶变换是数字信号处理领域一种很重要的算 ...
- 基于python的快速傅里叶变换FFT(一)
基于python的快速傅里叶变换FFT(一) FFT可以将一个信号变换到频域.有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了.这就是很多信号分析采用FFT变换的原因. ...
- Matlab如何进行利用离散傅里叶变换DFT (快速傅里叶变换FFT)进行频谱分析
文章目录 1. 定义 2. 变换和处理 3. 函数 4. 实例演示 例1:单频正弦信号(整数周期采样) 例2:单频正弦信号(非整数周期采样) 例3:含有直流分量的单频正弦信号 例4:正弦复合信号 例5 ...
- 快速傅里叶变换FFT进行频谱分析(matlab)
快速傅里叶变换FFT进行频谱分析(matlab) 本章摘要:FFT是离散傅立叶变换的快速算法,可以将一个信号变换到频域.有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了 ...
- Java编程实现快速傅里叶变换FFT
快速傅里叶变换的时间复杂度分析 1 快速傅里叶变换FFT 1.1 理论分析 1.1.1 离散傅里叶变换 1.1.2 快速傅里叶变换 1.2 编程实现 1.2.1 算法思想 1.2.2 实验结果 1 快 ...
- 快速傅里叶变换FFT C语言实现 可用于嵌入式系统进行模拟采样频谱分析
快速傅里叶变换C语言实现 模拟采样进行频谱分析 FFT是DFT的快速算法用于分析确定信号(时间连续可积信号.不一定是周期信号)的频率(或相位.此处不研究相位)成分,且傅里叶变换对应的 ω \omega ...
- 快速傅里叶变换python_基于python的快速傅里叶变换FFT(二)
基于python的快速傅里叶变换FFT(二) 本文在上一篇博客的基础上进一步探究正弦函数及其FFT变换. 知识点 FFT变换,其实就是快速离散傅里叶变换,傅立叶变换是数字信号处理领域一种很重要的算法. ...
- 图像傅里叶变换(快速傅里叶变换FFT)
学习DIP第7天,图像傅里叶变换 转载请标明出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对 ...
- 离散傅里叶变换 (DFT)、快速傅里叶变换 (FFT)
目录 离散傅里叶变换 (DFT) 离散傅里叶变换的基 离散傅里叶变换 快速傅里叶变换 (FFT) 卷积 线性时不变系统 傅里叶级数 参考文献 离散傅里叶变换 (DFT) 离散傅里叶变换的基 对于周期为 ...
最新文章
- python的难点_初学python的操作难点总结(新手必看篇)
- linux C 进程内部存储管理
- Linux文件查找命令具体解释-which whereis find locate
- microsoftexchange邮箱容量怎样看_企业邮箱申请注册的要求有哪些?_网站建设_创客网络...
- PAT (Top Level) Practise 1008 Airline Routes(Tarjan模版题)
- C++递归删除非空目录所有文件
- 【Alpha】Scrum Meeting 2
- QT中QString 类的使用--获取指定字符位置、截取子字符串等
- 台式机单硬盘安装黑苹果体验
- 互联网常见错误代码(如404)
- 选择第K大元素(快排、快选以及k-选取比较)
- uniapp 打包时报错:云端服务器返回错误,此应用DClound的Appdid非当前账号所有。
- 点位定位打开活动,到了某个点位后才可以打卡的活动,让打卡更具体,overflow: visible默认情况下,溢出是可见的
- HDU - 3194 Median
- 浅谈鸽巢原理的证明和简单应用
- 爬虫 — 爬取携程的航班信息
- 跟随自己,让自己的灵魂做主
- 4G容量U盘只显示2M多
- 表单打印html代码,Html表格代码实现打印
- 20221208AD域控服务器问题解决记录--lsass.exe上传流量异常