一文让你秒懂FFT(快速傅里叶变换)
引言 快速计算两个多项式的乘法
1.多项式乘法
例如
所以
那么我们该如何来储存一个多项式呢?最一般的方法就是储存多项式的系数,我们只需要把系数映射到一个表中,按顺序存储,这样的话,表中的第k个数字正好对应多项式的k阶项系数,我们称这种表示方法为多项式的系数表示法。
一般地,给定两个d阶多项式,
二者乘积应为2d阶多项式,并且这一算法,如果用naive的乘法分配律来算,时间复杂度为,因为多项式A的每一项都会跟B的每一项相乘。
问题来了,我们能改进这个算法吗?
2.多项式乘法的改进
这篇文章最奇妙的第一个想法,首先我们站在略微不同的角度来看待多项式,我们来看最简单的多项式,即一阶多项式(线性函数)
我们可以用两个系数来表示线性函数,即截距(0阶系数)和斜率(1阶系数),注意:一对系数唯一确定一条直线。那么,还有没有其他方法可以唯一确定一条直线呢?
这样的表示是很多的,我们这里用直线的两点表示,几何上我们学过:两点确定一条直线,事实上,高阶多项式也有类似的性质,即:任一d阶多项式都由d+1个点唯一确定,比如三个不同的点,只能唯一确定一个二次函数曲线。为了让大家信服这个性质,我们来证明一下它,假设我们有P(x)这个d阶多项式,通过了给定的d+1个点。
我们要证明,这个多项式的系数是唯一的,所以我们把这d+1个点代入多项式的方程,得到d+1个方程
将这个方程组用矩阵表示
矩阵
是范德蒙德矩阵,我们记作M。矩阵M可逆,只要这些点两两都不相同,故我们只需要证明矩阵M的行列式(范德蒙德矩阵)不为0,即可得出d阶行列式的系数是被d+1个点唯一确定的,从而多项式也是唯一的。
总结一下,我们现在有两种多项式的表示法,第一种是系数表示法,第二种是d+1个点表示法,称为值表示法。利用值表示法,多项式乘法变得非常简单,我们回到最开始的例子,
我们知道乘出来的多项式C(x)为4阶,所以需要5个点表示,我们现在只需要挑出5个点,将对应每个点的两个值相乘,得到C在每个点的函数值,根据我们前面证明的性质,这5个点确定了唯一的多项式,
可以看到,利用值表示法,我们计算多项式乘法的时间从一下子缩短到了!
3.快速多项式乘法
给定两个系数表示的d阶多项式
系数值 值系数
我们已经知道了值表示法计算多项式乘法更快,所以我们可以先计算两个多项式在2d+1个点上的值,然后将函数值一对对地乘起来,从而得到乘出来的值表示,然后最后一步,想办法将值转换回系数表示。
大体思路有了,问题是具体怎么实现?也就是:
如何把系数表示转换成值表示?
如何把值表示转换成系数表示?
对这两个问题的解答也就是这篇文章的目标——FFT和IFFT。
一 FFT(快速傅里叶变换)推导
1.求值
我们先来解决第一个问题:从系数表示到值表示,我们称这个问题为求值,给定多项式
和n个点,我们想计算多项式在这n个点上的值,n大于等于d+1,最粗暴的做法就是在X轴上随便挑选n个点,一个一个计算函数值,
我们当然可以这样做,但是你如果仔细看看,就发现这样的话,反而又回到了最开始的地方,因为每个点的计算都是,加起来是, 我们现在的问题是要寻找一个简单的方法,我们尝试着简化一下这个问题:举例比如,在n=4个点进行求值,那我们来想一下,有没有这样一对点:当你知道一个点的函数值时,另一个点的也可以立刻知道? 答案是肯定的,有!
如果我们选了,,那的值我们立马知道了,也是1,同样地,如果我们选了,那的值我们也立马知道了,都是4。
由此可见,我们只要取互为相反数的数对,这其中的机理非常简单:因为是个偶函数。
OK,问题来了,如果我们取,这个技巧还使适用吗?事实上,这个技巧依旧正确,但是我们在计算的时候需要在-x的函数值前面加一个负号。所以在这两个偶/奇函数的情形中,我们只需要计算一半数量的点就好了,因为剩下一半从奇偶性中就可以得到了。
对于一般的多项式,我们怎样使用这个技巧呢?举个例子
我们把这个多项式分为奇/偶函数两部分,我们把奇函数部分的x提出来,那么括号里的正是两个偶多项式函数,我们将两个括号内的部分分别命名为和,需要注意的是,这两个部分都是偶函数,这样的分解使得我们在计算一对相反数的函数值时,只需要计算其中一个,同时我们可以把两个部分都看做的函数,这样的话和的阶数都降到了2,比原来的5阶降低了许多。
推广一下这个想法,如果我们有一个n-1阶多项式,我们想知道它在n个点的函数值,我们可以把多项式分为奇/偶两部分,每部分都只有n/2-1阶,所以对于这俩只有原来一半阶数的多项式,我们只需要按照之前的求值方法进行计算即可,不同的是这次需要计算我们所给的点的平方的函数值,但我们只需要取一对对地相反数,那么在平方以后我们就只剩n/个点了。(这里其实就可以开始使用递归了,埋个伏笔)
总结:我们想计算多项式P在n个点上的值,这n个点是一对对的相反数,我们把多项式拆分成两部分,
从而我们有两个阶为n/2-1的多项式,每个多项式也只需要求n/2个点的值,我们只需要递归地求这两个小多项式的值,利用下方这两个公式带回去,就可以得到原多项式的n个值。
最终我们将得到原多项式的值表达,如果这一切都走得通,那么我们地时间复杂度仅为,因为这两个子问题都是原问题规模的一半,而且我们只需要线性时间来计算原多项式的值,相比于原来的是一个质的飞跃。
不过这里有一点问题,实际上在递归步骤:我们假设了每个多项式我们都使用相反数对来求值,但是对两个子问题而言,每个求值点都是平方数,所以都是正的,递归不成立。
那我们能不能把这些新的求值点也搞成相反数对呢?而这里,才是FFT最精妙的地方,只有一条路可走:我们把这些点都取成复数,我们还要专门挑一些复数,使得它们平方之后,依旧是正负成对出现的,那我们怎么取这些复数呢?我们来看一个例子逆向推导来找到答案。
需要个点来求值
这些点应该正负成对出现,我们写作,我们的递归算法需要在这两个点求子函数的值,那我们需要应当也是一对正负数对,所以有,再考虑一层递归,那么我们只有一个点:。
我们假设,那么这四个数应该是1,-1,i,-i,第二行就是1和-1,最下方就是1。从另一个角度来看,我们实际上是解了方程,而最上方四个点必须满足他们的四次方都等于1,事实上,我们知道方程有四个根,称为1的四个四次方根。
至少需要个点来求值
我们的递归算法每次递归后,点的个数要折半,所以我们取一个2的次方数,,那我们需要寻找8个数,形成4个正负对,并保正每个数字的8次方都是1,显然这8个数是1的八个八次方根。
需要个点去求值,我们选,这些点就相当于1的n个n次方根。关于为什么这些数可以,我做一些复数方面知识的补充:
补充:1的n个n次方根可以被解释为复平面上沿着单位圆等距排布的一系列点,任一相邻两点间的夹角为,从而这些点的最便捷的表达方法就是用欧拉公式表示成复指数。
我们定义,那么不同的i取值就代表了不同的单位复n次方根,所以当我们想在1的n次方根求值时,我们实际上是在上求值。
所以回到原来的问题:为啥n次方根就可以用于递归过程呢?有两个主要原因:
首先,我们要求的点是正负成对的,这里正好是这么一对;
另外,当我们考虑对应的递归低阶奇/偶函数时,n次方根有一个好性质,平方以后我们得到的正好是n/2个n/2次方根,他们也是正负配对的,完美适合递归;我们再平方,又得到n/4个n/4次方根,适用于下一层的递归,最终直到我们只剩一个点。
2.FFT算法及程序
下面终于是激动人心的FFT算法了!
FFT算法的输入是多项式的n个系数其中n是2的幂次,我们取为1的n次方根,递归的底层情况是n=1,此时我们只在一个点上求多项式的值。
递归的主要命令就是把多项式拆分成奇/偶函数两部分,两部分就是调用函数两次,此时这两个子多项式函数都是n/2阶的,所以对应的求值点将是1的n/2次方根。
我们假设递归调用的两部分函数值为和,然后我们把这两部分的函数值结合一下,计算出原多项式函数在对应的点的函数值,结合起来的核心思想就是利用正负对,不过这里要为n次方根略微修改一下我们的表达式,(为了方便写程序,这里的指标都是从0开始的。)此时应该写为,所以公式改写如下:
同时我们观察到,这里的正负点对是,所以我们可以把第二个式子再改写如下:
还有一个不可忽略的小细节:和上的第j个元素,正好对应了和
那么我们可以把我们的公式右侧全部写作和,这样就方便写程序了。
最终FFT输出的是原多项式在n个n次方根的值。下面我们用程序来实现上面的过程。
def FFT(P):# P- [po,P1,...,Pn-1]系数表示n=len(P)#n是2的幂次if n== l:return PW=e^(2πi/n)Pe,Po=P[::2],P[1::2]Ye,Yo= FFT(Pe), FFT(Po)y=[0]*nfor j in range(n/2):y[j] =ye[j] + wjyo[j]y[j + n/2] = ye[j]一wjyo[j]return y
三 IFFT算法
1.插值
把值表示转换为系数表示,这个过程叫做插值。
参考前面将求值表示为矩阵-向量乘积,我们用系数向量乘以点对应的(范德蒙德)矩阵,从而得到对应的值,因为FFT中是对应的第k个n次方根,所以我们把这个矩阵乘法改写如下,改写后的矩阵称为离散傅里叶变换(DFT)矩阵,而我们前面所说的FFT就是快速计算DFT和向量乘法的算法,在n次方根处求值其实就是DFT矩阵和向量乘法的特例。
插值实际上就是给定位置的函数值,计算函数的系数,写作矩阵就是DFT矩阵的逆和值表示向量相乘。
2.IFFT算法及程序
上下两矩阵结构一致,我们只需要把上矩阵的换成,就可以变为下矩阵了,这表明我们几乎可以在插值问题上套用FFT。
我们来对比一下区别,在求值过程中我们通过多项式系数和FFT算法,计算n次单位根处的函数值,这实际上是DFT矩阵和系数向量的乘法,其中,而在插值中,我们实际上是在使用逆FFT算法,逆FFT算法的输入是多项式在n次单位根处的函数值,输出多项式的系数,即反向操作FFT算法。
前面我们已经知道我们需要做一个DFT矩阵的逆和向量的乘法,求DFT矩阵的逆,我们只需要把原来矩阵的换成,这意味着逆FFT实际上和FFT的操作一模一样,只是原本的系数向量变成了值表示向量,而且换成了,就这样我们就得到了计算插值的逆FFT算法。超级简单!
下面展示一下IFFT算法的程序:
def IFFT(P):# P- [po,P1,...,Pn-1] 值表示n=len(P)#n是2的幂次 if n== l:return PW=(1/n)*e^(-2πi/n)Pe,Po=P[::2],P[1::2]Ye,Yo= IFFT(Pe), IFFT(Po)y=[0]*nfor j in range(n/2):y[j] =ye[j] + wjyo[j]y[j + n/2] = ye[j]一wjyo[j]return y
可以看出IFFT与FFT高度相同,只是调用函数从FFT变为IFFT,然后还有第6行略有区别,其他完全一样。
总结
把多项式用对应点的值表示
利用相反数来保证点成对出现
用1的n次单位复根,这样每次平方完,它们还是正负成对出现,
IFFT算法和FFT算法除了第6行以外一模一样
附视频链接:https://www.youtube.com/watch?v=h7apO7q16V0&feature=emb_logo
感兴趣的同学可以自行看看原视频,真的很通透,看完之后立马对傅里叶变换的理解上一个大台阶
一文让你秒懂FFT(快速傅里叶变换)相关推荐
- 【经典算法实现 44】理解二维FFT快速傅里叶变换 及 IFFT快速傅里叶逆变换(迭代法 和 递归法)
[经典算法实现 44]理解二维FFT快速傅里叶变换 及 IFFT快速傅里叶逆变换(迭代法 和 递归法) 一.二维FFTFFTFFT快速傅里叶变换 公式推导 二.二维FFTFFTFFT 及 IFFTIF ...
- FFT快速傅里叶变换 超详细的入门学习总结
FFT快速傅里叶变换 说明 本文创作的目的是为自己巩固该算法,加深印象并深入理解,同时也为FFT入门学者提供一份可鉴的学习总结. 原文链接:https://blog.csdn.net/qq_39565 ...
- FFT快速傅里叶变换C语言实现信号处理 对振动信号进行实现时域到频域的转换
FFT快速傅里叶变换C语言实现信号处理 对振动信号进行实现时域到频域的转换,可实现FFT8192个点或改成其他FFT1024.4096等等,可以直接运行,运行结果与matlab运行的一致,写好了注释, ...
- c语言fft乘法步骤,C语言实现FFT(快速傅里叶变换).doc
C语言实现FFT(快速傅里叶变换) 择蚁牙幸帆揣邓淌港烬粹甩滋整维含兔忿茂慨渔下餐随扼哇房坏鹅穆礼围引介害芝共茨恿把喜恤寇杖除冕嗓停揍猫调锚遭傀个碱晓频斌硕宾撕坪莱哩腊养掘蹄轴国繁蔬虞靡砖焙倍勾呸怀怒 ...
- 快速傅里叶变换c语言函数,C语言实现FFT(快速傅里叶变换)
while(1); } #include #include /********************************************************************* ...
- 如何 FFT(快速傅里叶变换) 求幅度、频率(超详细 含推导过程)
目录 如何 FFT(快速傅里叶变换) 求幅度.频率(超详细 含推导过程) 一. 打颗栗子 二. 求幅度 1. 快速傅里叶变换 2. 求出复数的绝对值 3. 归一化 小结 三. 求频率 1. 频率公式 ...
- FFT快速傅里叶变换的应用——画单边频谱图matlab
FFT快速傅里叶变换的应用--画单边频谱图matlab 快速傅里叶变换在数字信号处理里用的十分广泛,在matlab仿真中,处理信号的时频域变换十分有效,这里结合两个做过的仿真,来说一说fft的应用:画 ...
- FFT 快速傅里叶变换 初探
一直认为很高深的东西其实也并不很难. 以下内容部分来自qy大神的ppt,同时结合了自己的理解.但理解还不是很深,需要继续研究. 开头 首先什么是傅里叶变换:傅立叶变换能将满足一定条件的某个函数表示成三 ...
- FFT快速傅里叶变换详解
介绍 简而言之,这个东西用来做多项式乘法. 比如说,有两个多项式: 3x2+2x+1,2x2+x+43x^2+2x+1~,~2x^2+x+4 3x2+2x+1 , 2x2+x+4 那么他们乘起来就是 ...
最新文章
- 15万奖金强化学习赛事!Go-Bigger多智能体决策智能挑战赛来了!
- 笔记本Wifi连接出现“设置与网络连接不匹配”的解决方法
- Hibernate 4.3 ORM工具
- Source Insight 教程
- 即席和即兴_即兴说话小课堂
- c语言中文网 vc++6.0下载量_【新手必看】C语言开发环境,请查收!
- 2008安装完了找不到_【专业性】关于铸铝热水锅炉安装使用的思考
- QT学习-核心类列表-4、Qt WebKit Widgets 5、Qt3DCore
- python 对excel操作用法详解_Python对excel文档的操作方法详解
- gstreamer支持多摄像头的思路
- 分享5款2022年最好用的windows软件
- axios与ajax对比,AjAX 步骤和对比fetch和axios
- ISE如何生成msc文件,并写入flash中
- Yate for Mac(音乐标签管理工具)
- python判断两个矩形是否相交_使用Python判断线段是否与矩形相交
- luci html 页面,luci界面修改
- 浏览器突然访问不了某个网址或者提示无法访问此网站
- 默然学java(一)JAVA背景 JDK和JRE的关系
- 15、条件概率、全概率公式、贝叶斯公式、马尔科夫链
- 如何打造一场引爆朋友圈的母亲节营销活动
热门文章
- 百度地图实现自定义搜索
- 3D美术人员Technical Artist(TA技术美术)的学习之旅(1)
- Metaq原理与应用
- 第4篇 Fast AI深度学习课程——深度学习在回归预测、NLP等领域的应用
- 如何重新启动Windows的Explorer.exe(以及任务栏和“开始”菜单)
- Java SDK的作用
- AHK 键盘控制鼠标点击屏幕不同位置
- linux系统安装在u盘
- Google GSON GsonBuilder().setDateFormat(yyyy-MM-dd HH:mm:ss)不能格式化Data
- 梦之安魂曲 minisd_科技运动中妇女的安魂曲