FFT(快速傅里叶变换)算法

2023-11-08

功能

一次FFT的功能

O ( n log ⁡ n ) O(n\log n) O(nlogn)的时间将一个多项式的系数表达式变成点值表达式(这两种表达方式后文会提到)。

一次IFFT的功能

O ( n log ⁡ n ) O(n\log n) O(nlogn)的时间将一个多项式的点值表达式变成系数表达式(这两种表达方式后文会提到)。

总体功能

O ( n log ⁡ n ) O(n\log n) O(nlogn)的时间求两个多项式的乘积。

一个 n n n项的整式多项式一定可以表示成: f ( x ) = ∑ i = 0 n − 1 ( a i x i ) f(x)=\sum\limits_{i=0}^{n-1}(a_ix^i) f(x)=i=0n1(aixi)
(有些 a i a_i ai可能为 0 0 0

所以,一个系数 a a a的(有序)集合可以唯一确定一个多项式。
例如: a = { 1 , 2 , 0 , 3 , 5 } a=\{1,2,0,3,5\} a={1,2,0,3,5}表示的就是多项式: f ( x ) = 1 + 2 x + 3 x 3 + 5 x 4 f(x)=1+2x+3x^3+5x^4 f(x)=1+2x+3x3+5x4
这里 a = { 1 , 2 , 0 , 3 , 5 } a=\{1,2,0,3,5\} a={1,2,0,3,5} f ( x ) f(x) f(x)系数表达式

所以,所谓求两个多项式的乘积,就是已知两个多项式的系数表达式,求它们乘积的多项式的系数表达式

前置技能

(既然大家都这样说,我也这样说吧)

多项式的阶

之前说的 f ( x ) = ∑ i = 0 n − 1 ( a i x i ) f(x)=\sum\limits_{i=0}^{n-1}(a_ix^i) f(x)=i=0n1(aixi)中的 n n n就是它的阶,注意 n n n阶多项式不一定是 n n n次的,因为 a n − 1 a_{n-1} an1可能为 0 0 0

多项式的系数表达式

前面已说。

多项式的点值表达式

一个 n n n次多项式就是一个函数,取它图像上的 n + 1 n+1 n+1个不同的点就可以确定这个多项式。

例如 f ( x ) f(x) f(x)是个 4 4 4次多项式,取它的图像上的任意 5 5 5个不同的点: ( x 1 , f ( x 1 ) ) (x_1,f(x_1)) (x1,f(x1)) ( x 2 , f ( x 2 ) ) (x_2,f(x_2)) (x2,f(x2)),…, ( x 5 , f ( x 5 ) ) (x_5,f(x_5)) (x5,f(x5)),可以确定这个多项式的系数,因为可以列出一个 5 5 5元一次方程组解出系数。

于是一个 n n n次多项式的点值表达式就是它的图像上 n + 1 n+1 n+1个不同的点。
换句话说, n + 1 n+1 n+1个不同的点可以唯一确定一个 n n n次多项式。
(以上两句话式FFT和逆FFT的核心)

复数

在实数范围内,老师会告诉你负数没有平方根,所以我们为了让负数有平方根,将数的范围从实数扩展到了复数。
(实数也属于复数,复数另外一部分是虚数)

复数的基本单位

引入一个符号 i i i i 2 = − 1 i^2=-1 i2=1
于是任意一个复数都可以表示成 a + b i a+bi a+bi,其中 a a a b b b都是实数。
例如: x 2 = − 7 x^2=-7 x2=7的根是: x 1 = 7 i x_1=\sqrt 7i x1=7 i x 2 = − 7 i x_2=-\sqrt 7i x2=7 i

复数的运算

加减乘都和整式的运算是一样的,例如两个复数 z 1 = a 1 + b 1 i z_1=a_1+b_1i z1=a1+b1i z 2 = a 2 + b 2 i z_2=a_2+b_2i z2=a2+b2i相乘: z 1 z 2 = ( a 1 + b 1 i ) ( a 2 + b 2 i ) = ( a 1 a 2 − b 1 b 2 ) + ( a 1 b 2 + a 2 b 1 ) i z_1z_2=(a_1+b_1i)(a_2+b_2i)=(a_1a_2-b_1b_2)+(a_1b_2+a_2b_1)i z1z2=(a1+b1i)(a2+b2i)=(a1a2b1b2)+(a1b2+a2b1)i
除法这里不会用到,但也不难,可以分母实数化:

复数的除法
来自百度百科:复数除法

复平面

数轴可以表示一切实数,平面可以表示一切复数:
复平面
(其实这个图没有什么用)
在复平面内的一个点 ( x , y ) (x,y) (x,y)表示一个复数 x + y i x+yi x+yi

复根

定义

定义: ω n k = c o s ( 2 π n k ) + s i n ( 2 π n k ) i \omega_n^k=cos\left(\frac{2\pi}{n}k\right)+sin\left(\frac{2\pi}{n}k\right)i ωnk=cos(n2πk)+sin(n2πk)i
ω n 1 \omega_n^1 ωn1 n n n次单位复根。

很难懂是不是?把 ω 8 0 \omega_8^0 ω80,…, ω 8 7 \omega_8^7 ω87对应的点在复平面上画出来你就知道了。
8次单位复根
(由于几何画板的公式编辑太弱,所以只标了 A B C ABC ABC
A A A B B B C C C…对应的复数分别是 ω 8 0 \omega_8^0 ω80 ω 8 1 \omega_8^1 ω81 ω 8 2 \omega_8^2 ω82,…

为什么?数学必修四的单位圆与三角函数会告诉你的。

几个性质
  • ω n i ω n j = ω n i + j \omega_n^i\omega_n^j=\omega_n^{i+j} ωniωnj=ωni+j

证明:
由于 e i θ = c o s θ + s i n θ ⋅ i e^{i\theta}=cos\theta+sin\theta\cdot i eiθ=cosθ+sinθi(我不会证,貌似要用泰勒展开)
所以 ω n i = e 2 π n i \omega_n^i=e^{\frac{2\pi}{n}i} ωni=en2πi
所以 ω n i ω n j = e 2 π n i e 2 π n j = e 2 π n ( i + j ) = ω n i + j \omega_n^i\omega_n^j=e^{\frac{2\pi}{n}i}e^{\frac{2\pi}{n}j}=e^{\frac{2\pi}{n}(i+j)}=\omega_n^{i+j} ωniωnj=en2πien2πj=en2π(i+j)=ωni+j

  • ω 2 n 2 k = ω n k \omega_{2n}^{2k}=\omega_n^k ω2n2k=ωnk
    理解:它们对应的点是一样的

证明:
ω 2 n 2 k = c o s ( 2 π 2 n 2 k ) + s i n ( 2 π 2 n 2 k ) i = c o s ( 2 π n k ) + s i n ( 2 π n k ) i = ω n k \omega_{2n}^{2k}=cos\left(\frac{2\pi}{2n}2k\right)+sin\left(\frac{2\pi}{2n}2k\right)i=cos\left(\frac{2\pi}{n}k\right)+sin\left(\frac{2\pi}{n}k\right)i=\omega_n^k ω2n2k=cos(2n2π2k)+sin(2n2π2k)i=cos(n2πk)+sin(n2πk)i=ωnk

  • ω n k + n 2 = − ω n k \omega_n^{k+\frac{n}{2}}=-\omega_n^k ωnk+2n=ωnk n n n是偶数)
    理解:它们对应的点关于原点对称。

证明: ω n k + n 2 = c o s ( 2 π n k + π ) + s i n s ( 2 π n k + π ) i = − c o s ( 2 π n k ) − s i n ( 2 π n k ) i = − ω n k \omega_{n}^{k+\frac{n}{2}}=cos\left(\frac{2\pi}{n}k+\pi\right)+sins\left(\frac{2\pi}{n}k+\pi\right)i=-cos\left(\frac{2\pi}{n}k\right)-sin\left(\frac{2\pi}{n}k\right)i=-\omega_n^k ωnk+2n=cos(n2πk+π)+sins(n2πk+π)i=cos(n2πk)sin(n2πk)i=ωnk

  • ω n k + n = ω n k \omega_n^{k+n}=\omega_n^k ωnk+n=ωnk
    理解:转了一圈回到原来的点。

证明:同上一个证明

  • ∑ i = 0 n − 1 ( ω n k ) i = 0 \sum\limits_{i=0}^{n-1}(\omega_n^k)^i=0 i=0n1(ωnk)i=0 k ≠ 0 k\neq 0 k=0)(求和引理)
    理解:每个点和它关于原点对称的点抵消了。

证明:
∑ i = 0 n − 1 ( ω n k ) i = 1 + ω n k + ( ω n k ) 2 + . . . + ( ω n k ) n − 1 = ( ω n k ) n − 1 ω n k − 1 = ω n k n − 1 ω n k − 1 = 1 − 1 ω n k − 1 = 0 \sum\limits_{i=0}^{n-1}(\omega_n^k)^i=1+\omega_n^k+(\omega_n^k)^2+...+(\omega_n^k)^{n-1}=\frac{(\omega_n^k)^n-1}{\omega_n^k-1}=\frac{\omega_n^{kn}-1}{\omega_n^k-1}=\frac{1-1}{\omega_n^k-1}=0 i=0n1(ωnk)i=1+ωnk+(ωnk)2+...+(ωnk)n1=ωnk1(ωnk)n1=ωnk1ωnkn1=ωnk111=0

求多项式乘积的基本步骤

已知 k 1 k_1 k1阶多项式 f ( x ) f(x) f(x) k 2 k_2 k2阶多项式 g ( x ) g(x) g(x)的系数表达式。
我们要求的是 k 1 + k 2 k_1+k_2 k1+k2阶多项式 h ( x ) = f ( x ) ⋅ g ( x ) h(x)=f(x)\cdot g(x) h(x)=f(x)g(x)的系数表达式。

  1. 统一两个多项式的阶数为 n n n,要保证 n n n 2 2 2的幂。(系数补零即可,为什么一会说)
  2. n n n个不同的值 x x x,代入 f ( x ) f(x) f(x) g ( x ) g(x) g(x)中,得到 f ( x ) f(x) f(x) g ( x ) g(x) g(x)的点值表达式: S f ( x ) = { ( x 1 , f ( x 1 ) ) , ( x 2 , f ( x 2 ) ) , . . . , ( x n , f ( x n ) ) } S_{f(x)}=\{(x_1,f(x_1)),(x_2,f(x_2)),...,(x_n,f(x_n))\} Sf(x)={(x1,f(x1)),(x2,f(x2)),...,(xn,f(xn))} S g ( x ) = { ( x 1 , g ( x 1 ) ) , ( x 2 , g ( x 2 ) ) , . . . , ( x n , g ( x n ) ) } S_{g(x)}=\{(x_1,g(x_1)),(x_2,g(x_2)),...,(x_n,g(x_n))\} Sg(x)={(x1,g(x1)),(x2,g(x2)),...,(xn,g(xn))}(两次FFT得到)
  3. 计算 h ( x ) h(x) h(x)的点值表达式: S h ( x ) = { ( x 1 , f ( x 1 ) ⋅ g ( x 1 ) ) , ( x 2 , f ( x 2 ) ⋅ g ( x 2 ) ) , . . . , ( x n , f ( x n ) ⋅ g ( x n ) ) } S_{h(x)}=\{(x_1,f(x_1)\cdot g(x_1)),(x_2,f(x_2)\cdot g(x_2)),...,(x_n,f(x_n)\cdot g(x_n))\} Sh(x)={(x1,f(x1)g(x1)),(x2,f(x2)g(x2)),...,(xn,f(xn)g(xn))}
  4. 通过 h ( x ) h(x) h(x)的点值表达式求 h ( x ) h(x) h(x)的系数表达式。
    (一次IFFT得到)

忽略极大的常数,暴力的时间复杂度是 O ( n 2 ) O(n^2) O(n2),FFT可以把它优化到 O ( n log ⁡ n ) O(n\log n) O(nlogn)

FFT(IFFT)是通过计算一半的点值表达式得到另一半,要计算的那一半重复前面的步骤。

FFT

[特别提醒]

  • 因为点值表达式中的 x x x集合取何值无影响,所以取算的越快的越好。
  • 一次FFT(快速傅里叶变换)是将一个多项式的系数表达式集合变成特定( x x x ω n 0 , . . . , ω n n − 1 \omega_n^0,...,\omega_n^{n-1} ωn0,...,ωnn1)点值表达式中的 y y y集合。
  • 一次IFFT(快速傅里叶变换逆变换)是将一个多项式的特定( x x x ω n 0 , . . . , ω n n − 1 \omega_n^0,...,\omega_n^{n-1} ωn0,...,ωnn1)点值表达式中的 y y y集合变成系数表达式集合。
  • 注意 n n n 2 2 2的幂。

递归版FFT

核心公式

我们代入求点值表达式的 n n n x x x是: ω n 0 , . . . , ω n n − 1 \omega_n^0,...,\omega_n^{n-1} ωn0,...,ωnn1

设多项式是 A ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a n − 1 x n − 1 A(x)=a_0+a_1x+a_2x^2+...+a_{n-1}x^{n-1} A(x)=a0+a1x+a2x2+...+an1xn1
A 0 ( x ) = a 0 + a 2 x + a 4 x 2 + . . . + a n − 2 x n 2 − 1 A_0(x)=a_0+a_2x+a_4x^2+...+a_{n-2}x^{\frac{n}{2}-1} A0(x)=a0+a2x+a4x2+...+an2x2n1
A 1 ( x ) = a 1 + a 3 x + a 5 x 2 + . . . + a n − 1 x n 2 − 1 A_1(x)=a_1+a_3x+a_5x^2+...+a_{n-1}x^{\frac{n}{2}-1} A1(x)=a1+a3x+a5x2+...+an1x2n1
显然 A ( x ) = A 0 ( x 2 ) + x A 1 ( x 2 ) A(x)=A_0(x^2)+xA_1(x^2) A(x)=A0(x2)+xA1(x2)(可以自己带进去算一下)

那么 A ( ω n k ) = A 0 ( ω n 2 k ) + ω n k A 1 ( ω n 2 k ) = A 0 ( ω n 2 k ) + ω n k A 1 ( ω n 2 k ) A(\omega_n^k)=A_0(\omega_n^{2k})+\omega_n^kA_1(\omega_n^{2k})=A_0(\omega_{\frac{n}{2}}^{k})+\omega_n^kA_1(\omega_{\frac{n}{2}}^{k}) A(ωnk)=A0(ωn2k)+ωnkA1(ωn2k)=A0(ω2nk)+ωnkA1(ω2nk)
A ( ω n k + n 2 ) = A 0 ( ω n 2 k + n ) + ω n k + n 2 A 1 ( ω n 2 k + n ) = A 0 ( ω n 2 k ) − ω n k A 1 ( ω n 2 k ) = A 0 ( ω n 2 k ) − ω n k A 1 ( ω n 2 k ) A(\omega_n^{k+\frac{n}{2}})=A_0(\omega_n^{2k+n})+\omega_n^{k+\frac{n}{2}}A_1(\omega_n^{2k+n})=A_0(\omega_{n}^{2k})-\omega_n^kA_1(\omega_{n}^{2k})=A_0(\omega_{\frac{n}{2}}^{k})-\omega_n^kA_1(\omega_{\frac{n}{2}}^{k}) A(ωnk+2n)=A0(ωn2k+n)+ωnk+2nA1(ωn2k+n)=A0(ωn2k)ωnkA1(ωn2k)=A0(ω2nk)ωnkA1(ω2nk)

这两个只有正负号不同!

算法流程

我们定义FFT(A,n),表示将系数表达式的系数集合 A A A转换为点值表达式的 y y y值集合(代入的 x x x ω n 0 , ω n 1 , . . . ω n n − 1 \omega_n^0,\omega_n^1,...\omega_n^{n-1} ωn0,ωn1,...ωnn1)。
那么,FFT(A,n)中,先提出 A 0 A_0 A0 A 1 A_1 A1,再执行FFT(A0,n/2)FFT(A1,n/2)
执行完后的 A 0 A_0 A0 A 1 A_1 A1已经变成了当 “ 代入的 x x x ω n 2 0 , ω n 2 1 , . . . ω n 2 n 2 − 1 \omega_\frac{n}{2}^0,\omega_\frac{n}{2}^1,...\omega_\frac{n}{2}^{\frac{n}{2}-1} ω2n0,ω2n1,...ω2n2n1 ” 时,对应的 y y y的集合。
然后就可以循环从 0 0 0 n 2 \frac{n}{2} 2nA[i]=A0[i]+w*A1[i]A[i+n/2]=A0[i]-w*A1[i]

代码

等讲了IFFT的递归版一起看。

非递归版FFT

算法

非递归版展示
(来自不知名的大佬

这是 n = 8 n=8 n=8时的递归FFT的系数示意图。
发现最后得到的系数序列,每个数的二进制反转后恰好是最开始的序列(为什么?用心去感受一下吧)。

所以只需要把最开始的系数变成最后的样子,再一层层向上合并即可。
也就是说,把最开始的每个系数和它二进制反转后的数交换位置。

定义R[i]表示i的二进制反转后的数,Li的二进制位数(即 log ⁡ 2 n \log_2 n log2n),那么有:
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1))

下面是解释:
R[i>>1]表示i除去最后一位后前面几位的反转,那么把它和i的最后一位换个位置就好了。

代码

等讲了IFFT的非递归版一起看。

IFFT

FFT的矩阵表达

( y 0 y 1 y 2 y 3 ⋮ y n − 1 ) = ( ω n 0 ω n 0 ω n 0 ω n 0 ⋯ ω n 0 ω n 0 ω n 1 ω n 2 ω n 3 ⋯ ω n n − 1 ω n 0 ω n 2 ω n 4 ω n 6 ⋯ ω n 2 ( n − 1 ) ω n 0 ω n 3 ω n 6 ω n 9 ⋯ ω n 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ ω n 0 ω n n − 1 ω n 2 ( n − 1 ) ω n 3 ( n − 1 ) ⋯ ω n ( n − 1 ) ( n − 1 ) ) × ( a 0 a 1 a 2 a 3 ⋮ a n − 1 ) \left( \begin{matrix} y_0\\ \\ y_1\\ \\ y_2\\ \\ y_3\\ \\ \vdots\\ \\ y_{n-1} \end{matrix} \right)= \left( \begin{matrix} \omega_n^0 & \omega_n^0 & \omega_n^0 & \omega_n^0 & \cdots & \omega_n^0\\ \\ \omega_n^0 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \cdots & \omega_n^{n-1}\\ \\ \omega_n^0 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \cdots & \omega_n^{2(n-1)}\\ \\ \omega_n^0 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \cdots & \omega_n^{3(n-1)}\\ \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots\\ \\ \omega_n^0 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \cdots & \omega_n^{(n-1)(n-1)}\\ \end{matrix} \right)\times\\ \left( \begin{matrix} a_0\\ \\ a_1\\ \\ a_2\\ \\ a_3\\ \\ \vdots\\ \\ a_{n-1} \end{matrix} \right) y0y1y2y3yn1=ωn0ωn0ωn0ωn0ωn0ωn0ωn1ωn2ωn3ωnn1ωn0ωn2ωn4ωn6ωn2(n1)ωn0ωn3ωn6ωn9ωn3(n1)ωn0ωnn1ωn2(n1)ωn3(n1)ωn(n1)(n1)×a0a1a2a3an1

FFT可以表示为这样, { y } \{y\} {y}是点值表达式的 y y y值集合, { a } \{a\} {a}是系数表达式的系数集合。
(矩阵乘法可以自己百度一下,在这里就是 y k = ∑ i = 0 n − 1 ( a i ω n k i ) y_k=\sum\limits_{i=0}^{n-1}\left(a_i\omega_n^{ki}\right) yk=i=0n1(aiωnki)

例如: y 2 = f ( x 2 ) = f ( ω n 2 ) = a 0 ( ω n 2 ) 0 + a 1 ( ω n 2 ) 1 + a 2 ( ω n 2 ) 2 + . . . + a n − 1 ( ω n 2 ) n − 1 y_2=f(x_2)=f(\omega_n^2)=a_0(\omega_n^2)^0+a_1(\omega_n^2)^1+a_2(\omega_n^2)^2+...+a_{n-1}(\omega_n^2)^{n-1} y2=f(x2)=f(ωn2)=a0(ωn2)0+a1(ωn2)1+a2(ωn2)2+...+an1(ωn2)n1 = a 0 ω n 0 + a 1 ω n 2 + a 2 ω n 4 + . . . + a n − 1 ω n 2 ( n − 1 ) =a_0\omega_n^0+a_1\omega_n^2+a_2\omega_n^4+...+a_{n-1}\omega_n^{2(n-1)} =a0ωn0+a1ωn2+a2ωn4+...+an1ωn2(n1) = ∑ i = 0 n − 1 ( a i ω n 2 i ) =\sum\limits_{i=0}^{n-1}\left(a_i\omega_n^{2i}\right) =i=0n1(aiωn2i)

IFFT的矩阵表达

V = ( ω n 0 ω n 0 ω n 0 ω n 0 ⋯ ω n 0 ω n 0 ω n 1 ω n 2 ω n 3 ⋯ ω n n − 1 ω n 0 ω n 2 ω n 4 ω n 6 ⋯ ω n 2 ( n − 1 ) ω n 0 ω n 3 ω n 6 ω n 9 ⋯ ω n 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ ω n 0 ω n n − 1 ω n 2 ( n − 1 ) ω n 3 ( n − 1 ) ⋯ ω n ( n − 1 ) ( n − 1 ) ) V=\left( \begin{matrix} \omega_n^0 & \omega_n^0 & \omega_n^0 & \omega_n^0 & \cdots & \omega_n^0\\ \\ \omega_n^0 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \cdots & \omega_n^{n-1}\\ \\ \omega_n^0 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \cdots & \omega_n^{2(n-1)}\\ \\ \omega_n^0 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \cdots & \omega_n^{3(n-1)}\\ \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots\\ \\ \omega_n^0 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \cdots & \omega_n^{(n-1)(n-1)}\\ \end{matrix} \right) V=ωn0ωn0ωn0ωn0ωn0ωn0ωn1ωn2ωn3ωnn1ωn0ωn2ωn4ωn6ωn2(n1)ωn0ωn3ωn6ωn9ωn3(n1)ωn0ωnn1ωn2(n1)ωn3(n1)ωn(n1)(n1)
( y 0 y 1 y 2 y 3 ⋮ y n − 1 ) = V × ( a 0 a 1 a 2 a 3 ⋮ a n − 1 ) \left( \begin{matrix} y_0\\ \\ y_1\\ \\ y_2\\ \\ y_3\\ \\ \vdots\\ \\ y_{n-1} \end{matrix} \right)= V\times\\ \left( \begin{matrix} a_0\\ \\ a_1\\ \\ a_2\\ \\ a_3\\ \\ \vdots\\ \\ a_{n-1} \end{matrix} \right) y0y1y2y3yn1=V×a0a1a2a3an1
那么 ( y 0 y 1 y 2 y 3 ⋮ y n − 1 ) × V − 1 = ( a 0 a 1 a 2 a 3 ⋮ a n − 1 ) \left( \begin{matrix} y_0\\ \\ y_1\\ \\ y_2\\ \\ y_3\\ \\ \vdots\\ \\ y_{n-1} \end{matrix} \right)\times V^{-1}= \left( \begin{matrix} a_0\\ \\ a_1\\ \\ a_2\\ \\ a_3\\ \\ \vdots\\ \\ a_{n-1} \end{matrix} \right) y0y1y2y3yn1×V1=a0a1a2a3an1

也就是说,我们只要构造出 V − 1 V^{-1} V1,IFFT就解决了。


换句话说,要构造一个矩阵 V − 1 V^{-1} V1,使得 V × V − 1 = A V\times V^{-1}=A V×V1=A A A A是单位矩阵)
其中 A = ( 1 0 0 ⋯ 0 0 1 0 ⋯ 0 0 0 1 ⋯ 0 ⋮ ⋮ ⋮ ⋱ ⋮ 0 0 0 ⋯ 1 ) A= \left( \begin{matrix} 1 & 0 & 0 & \cdots & 0\\ 0 & 1 & 0 & \cdots & 0\\ 0 & 0 & 1 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & 1 \end{matrix} \right) A=1000010000100001

(计算一下会发现任何矩阵乘 A A A都是它本身)


于是傅里叶说,
V − 1 = ( 1 n ω n 0 1 n ω n 0 1 n ω n 0 1 n ω n 0 ⋯ 1 n ω n 0 1 n ω n 0 1 n ω n − 1 1 n ω n − 2 1 n ω n − 3 ⋯ 1 n ω n − ( n − 1 ) 1 n ω n 0 1 n ω n − 2 1 n ω n − 4 1 n ω n − 6 ⋯ 1 n ω n − 2 ( n − 1 ) 1 n ω n 0 1 n ω n − 3 1 n ω n − 6 1 n ω n − 9 ⋯ 1 n ω n − 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ 1 n ω n 0 1 n ω n − ( n − 1 ) 1 n ω n − 2 ( n − 1 ) 1 n ω n − 3 ( n − 1 ) ⋯ 1 n ω n − ( n − 1 ) ( n − 1 ) ) V^{-1}= \left( \begin{matrix} \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^0 & \cdots & \frac{1}{n}\omega_n^0\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-1} & \frac{1}{n}\omega_n^{-2} & \frac{1}{n}\omega_n^{-3} & \cdots & \frac{1}{n}\omega_n^{-(n-1)}\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-2} & \frac{1}{n}\omega_n^{-4} & \frac{1}{n}\omega_n^{-6} & \cdots & \frac{1}{n}\omega_n^{-2(n-1)}\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-3} & \frac{1}{n}\omega_n^{-6} & \frac{1}{n}\omega_n^{-9} & \cdots & \frac{1}{n}\omega_n^{-3(n-1)}\\ \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-(n-1)} & \frac{1}{n}\omega_n^{-2(n-1)} & \frac{1}{n}\omega_n^{-3(n-1)} & \cdots & \frac{1}{n}\omega_n^{-(n-1)(n-1)}\\ \end{matrix} \right) V1=n1ωn0n1ωn0n1ωn0n1ωn0n1ωn0n1ωn0n1ωn1n1ωn2n1ωn3n1ωn(n1)n1ωn0n1ωn2n1ωn4n1ωn6n1ωn2(n1)n1ωn0n1ωn3n1ωn6n1ωn9n1ωn3(n1)n1ωn0n1ωn(n1)n1ωn2(n1)n1ωn3(n1)n1ωn(n1)(n1)

简单点说,(下标从零开始) V i , j = ω n i j V_{i,j}=\omega_n^{ij} Vi,j=ωnij V − 1 i , j = 1 n ω n − i j V^{-1}{}_{i,j}=\frac{1}{n}\omega_n^{-ij} V1i,j=n1ωnij


接下来要证明 V × V − 1 = A = ( 1 0 0 ⋯ 0 0 1 0 ⋯ 0 0 0 1 ⋯ 0 ⋮ ⋮ ⋮ ⋱ ⋮ 0 0 0 ⋯ 1 ) V\times V^{-1}=A=\left( \begin{matrix} 1 & 0 & 0 & \cdots & 0\\ 0 & 1 & 0 & \cdots & 0\\ 0 & 0 & 1 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & 1 \end{matrix} \right) V×V1=A=1000010000100001

根据矩阵乘法的定义, A x , y = ∑ i = 0 n − 1 ( V x , i V − 1 i , y ) A_{x,y}=\sum\limits_{i=0}^{n-1}(V_{x,i}V^{-1}{}_{i,y}) Ax,y=i=0n1(Vx,iV1i,y) = ∑ i = 0 n − 1 ( ω n x i 1 n ω n − i y ) =\sum\limits_{i=0}^{n-1}\left(\omega_n^{xi}\frac{1}{n}\omega_n^{-iy}\right) =i=0n1(ωnxin1ωniy) = 1 n ∑ i = 0 n − 1 ( ω n x − y ) i =\frac{1}{n}\sum\limits_{i=0}^{n-1}(\omega_n^{x-y})^i =n1i=0n1(ωnxy)i

x = y x=y x=y时, ω n x − y = 1 \omega_n^{x-y}=1 ωnxy=1 A i , j = 1 A_{i,j}=1 Ai,j=1
x ≠ y x\neq y x=y时,根据求和引理, A i , j = 0 A_{i,j}=0 Ai,j=0

得证。


综上所述:

  • FFT
    ( y 0 y 1 y 2 y 3 ⋮ y n − 1 ) = ( a 0 a 1 a 2 a 3 ⋮ a n − 1 ) × ( ω n 0 ω n 0 ω n 0 ω n 0 ⋯ ω n 0 ω n 0 ω n 1 ω n 2 ω n 3 ⋯ ω n n − 1 ω n 0 ω n 2 ω n 4 ω n 6 ⋯ ω n 2 ( n − 1 ) ω n 0 ω n 3 ω n 6 ω n 9 ⋯ ω n 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ ω n 0 ω n n − 1 ω n 2 ( n − 1 ) ω n 3 ( n − 1 ) ⋯ ω n ( n − 1 ) ( n − 1 ) ) \left( \begin{matrix} y_0\\ \\ y_1\\ \\ y_2\\ \\ y_3\\ \\ \vdots\\ \\ y_{n-1} \end{matrix} \right)= \left( \begin{matrix} a_0\\ \\ a_1\\ \\ a_2\\ \\ a_3\\ \\ \vdots\\ \\ a_{n-1} \end{matrix} \right)\times\\ \left( \begin{matrix} \omega_n^0 & \omega_n^0 & \omega_n^0 & \omega_n^0 & \cdots & \omega_n^0\\ \\ \omega_n^0 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \cdots & \omega_n^{n-1}\\ \\ \omega_n^0 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \cdots & \omega_n^{2(n-1)}\\ \\ \omega_n^0 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \cdots & \omega_n^{3(n-1)}\\ \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots\\ \\ \omega_n^0 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \cdots & \omega_n^{(n-1)(n-1)}\\ \end{matrix} \right) y0y1y2y3yn1=a0a1a2a3an1×ωn0ωn0ωn0ωn0ωn0ωn0ωn1ωn2ωn3ωnn1ωn0ωn2ωn4ωn6ωn2(n1)ωn0ωn3ωn6ωn9ωn3(n1)ωn0ωnn1ωn2(n1)ωn3(n1)ωn(n1)(n1)
  • IFFT
    ( a 0 a 1 a 2 a 3 ⋮ a n − 1 ) = ( y 0 y 1 y 2 y 3 ⋮ y n − 1 ) × ( 1 n ω n 0 1 n ω n 0 1 n ω n 0 1 n ω n 0 ⋯ 1 n ω n 0 1 n ω n 0 1 n ω n − 1 1 n ω n − 2 1 n ω n − 3 ⋯ 1 n ω n − ( n − 1 ) 1 n ω n 0 1 n ω n − 2 1 n ω n − 4 1 n ω n − 6 ⋯ 1 n ω n − 2 ( n − 1 ) 1 n ω n 0 1 n ω n − 3 1 n ω n − 6 1 n ω n − 9 ⋯ 1 n ω n − 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ 1 n ω n 0 1 n ω n − ( n − 1 ) 1 n ω n − 2 ( n − 1 ) 1 n ω n − 3 ( n − 1 ) ⋯ 1 n ω n − ( n − 1 ) ( n − 1 ) ) \left( \begin{matrix} a_0\\ \\ a_1\\ \\ a_2\\ \\ a_3\\ \\ \vdots\\ \\ a_{n-1} \end{matrix} \right)= \left( \begin{matrix} y_0\\ \\ y_1\\ \\ y_2\\ \\ y_3\\ \\ \vdots\\ \\ y_{n-1} \end{matrix} \right)\times\left( \begin{matrix} \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^0 & \cdots & \frac{1}{n}\omega_n^0\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-1} & \frac{1}{n}\omega_n^{-2} & \frac{1}{n}\omega_n^{-3} & \cdots & \frac{1}{n}\omega_n^{-(n-1)}\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-2} & \frac{1}{n}\omega_n^{-4} & \frac{1}{n}\omega_n^{-6} & \cdots & \frac{1}{n}\omega_n^{-2(n-1)}\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-3} & \frac{1}{n}\omega_n^{-6} & \frac{1}{n}\omega_n^{-9} & \cdots & \frac{1}{n}\omega_n^{-3(n-1)}\\ \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots\\ \\ \frac{1}{n}\omega_n^0 & \frac{1}{n}\omega_n^{-(n-1)} & \frac{1}{n}\omega_n^{-2(n-1)} & \frac{1}{n}\omega_n^{-3(n-1)} & \cdots & \frac{1}{n}\omega_n^{-(n-1)(n-1)}\\ \end{matrix} \right) a0a1a2a3an1=y0y1y2y3yn1×n1ωn0n1ωn0n1ωn0n1ωn0n1ωn0n1ωn0n1ωn1n1ωn2n1ωn3n1ωn(n1)n1ωn0n1ωn2n1ωn4n1ωn6n1ωn2(n1)n1ωn0n1ωn3n1ωn6n1ωn9n1ωn3(n1)n1ωn0n1ωn(n1)n1ωn2(n1)n1ωn3(n1)n1ωn(n1)(n1)

算法流程

既然构造出来了 V − 1 V^{-1} V1,我们就知道要代入计算的 x x x集合就是:
{ ω n 0 , ω n − 1 , . . . , ω n − ( n − 1 ) } \{\omega_n^0,\omega_n^{-1},...,\omega_n^{-(n-1)}\} {ωn0,ωn1,...,ωn(n1)}

为了减少误差,最后统一乘 1 n \frac{1}{n} n1

把 “ 求多项式乘积的基本步骤 ” 中的第3步得到的 h ( x ) h(x) h(x)的点值表达式的 y y y集合当做一个多项式的系数表达式集合,用一次FFT求出 x x x集合是 { ω n 0 , ω n − 1 , . . . , ω n − ( n − 1 ) } \{\omega_n^0,\omega_n^{-1},...,\omega_n^{-(n-1)}\} {ωn0,ωn1,...,ωn(n1)}时,这个多项式的点值表达式的 y y y集合,就是 h ( x ) h(x) h(x)系数集合的 n n n

还记得FFT算法流程的这一步吗:
A[i]=A0[i]+w*A1[i]A[i+n/2]=A0[i]-w*A1[i]

将它变为这样就是IFFT了:
A[i]=A0[i]-w*A1[i]A[i+n/2]=A0[i]+w*A1[i]

现在知道为什么代码要一起展示了,因为只需在FFT函数中加一个参数就可以实现逆变换了。

代码

看下面。

代码

大整数乘法一般的时间复杂度是 O ( n 2 ) O(n^2) O(n2),把两个大整数看成两个多项式的系数,求它们的乘积,最后处理进位,就可以做到 O ( n log ⁡ n ) O(n\log n) O(nlogn)了。

递归版

据说递归版要爆空间(我这道题和洛谷上的那道都用递归的过了),所以大家都写非递归版。

#include<cmath>
#include<cstdio>
#include<cstring>

#define LOG 17
#define MAXN (1<<LOG)
int res[MAXN+5];
char x[MAXN+5],y[MAXN+5];

struct Complex{
    double x,y;//x+yi
    Complex(){x=y=0;}
    Complex(double a,double b):x(a),y(b){}
    Complex operator + (Complex b)const{return Complex(x+b.x,y+b.y);}
    Complex operator - (Complex b)const{return Complex(x-b.x,y-b.y);}
    Complex operator * (Complex b)const{return Complex(x*b.x-y*b.y,y*b.x+x*b.y);}
}A0[MAXN+5],B0[MAXN+5];
//复数类,好像C++有一个叫complex的库

#define PI acos(-1)
void FFT(Complex *A,int len,int sign){
    if(len==1)
        return;
    int mid=len>>1;
    Complex A1[mid+5],A2[mid+5];//按奇偶分离系数到A1和A2
    for(int i=0;i<mid;i++)
        A1[i]=A[i<<1],A2[i]=A[i<<1|1];
    FFT(A1,mid,sign),FFT(A2,mid,sign);
    for(int i=0;i<mid;i++){
        Complex w(cos(2.0*PI/len*i),sign*sin(2.0*PI/len*i));
        //w是len次单位复根的i次方
        //sign=-1是逆变换
        A[i]=A1[i]+w*A2[i],A[i+mid]=A1[i]-w*A2[i];
    }
}

int main(){
    while(~scanf("%s%s",x+1,y+1)){
        int len1=strlen(x+1),len2=strlen(y+1),N=1;
        while(N<len1+len2)
            N<<=1;
        //统一长度为2的幂
        for(int i=0;i<len1;i++)
            A0[i]=Complex(x[len1-i]-'0',0);
        for(int i=0;i<len2;i++)
            B0[i]=Complex(y[len2-i]-'0',0);
        //倒着存可以避免很多恶心的问题
        FFT(A0,N,1);
        FFT(B0,N,1);
        for(int i=0;i<N;i++)
            A0[i]=A0[i]*B0[i];
        //得到乘积多项式的点值表达式
        FFT(A0,N,-1);
        for(int i=0;i<N;i++)
            res[i+1]=int(A0[i].x/N+0.5);
        //注意最后统一除以n,为避免精度误差,+0.5再取整
        for(int i=1;i<=N;i++)
            res[i+1]+=res[i]/10,res[i]%=10;
        while(N>1&&res[N]==0)
            N--;
        //处理进位和前导零
        for(int i=N;i>=1;i--)
            putchar(res[i]+'0');
        putchar('\n');
        memset(A0,0,sizeof A0);
        memset(B0,0,sizeof B0);
        memset(res,0,sizeof res);
    }
}

非递归版

建议写这种。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define LOG 17
#define MAXN (1<<LOG)
int res[MAXN+5];
char x[MAXN+5],y[MAXN+5];

struct Complex{
    double x,y;//x+yi
    Complex(){x=y=0;}
    Complex(double a,double b):x(a),y(b){}
    Complex operator + (Complex b)const{return Complex(x+b.x,y+b.y);}
    Complex operator - (Complex b)const{return Complex(x-b.x,y-b.y);}
    Complex operator * (Complex b)const{return Complex(x*b.x-y*b.y,y*b.x+x*b.y);}
}A0[MAXN+5],B0[MAXN+5];

#define PI acos(-1)
int R[MAXN+5];
void FFT(Complex *A,int len,int sign){
    for(int i=0;i<len;i++)
        if(i<R[i])//不加的话会swap两次,最后什么都没有发生
            swap(A[i],A[R[i]]);
    //调整成最后的顺序
    for(int mid=1;mid<len;mid<<=1)//枚举当前要处理的区间长度的一半
        for(int i=0;i<len;i+=mid<<1)//每2*mid的长度为一段,分开处理
            for(int j=0;j<mid;j++){//处理当前2*mid长度的区间
                Complex w(cos(PI/mid*j),sign*sin(PI/mid*j));//2.0被mid消掉了
                Complex tmp1=A[i+j],tmp2=A[i+j+mid];
                A[i+j]=tmp1+w*tmp2;
                A[i+j+mid]=tmp1-w*tmp2;
            }
}

int main(){
    while(~scanf("%s%s",x+1,y+1)){
        int len1=strlen(x+1),len2=strlen(y+1),N=1,Log=0;
        while(N<len1+len2)
            N<<=1,Log++;
        for(int i=0;i<len1;i++)
            A0[i]=Complex(x[len1-i]-'0',0);
        for(int i=0;i<len2;i++)
            B0[i]=Complex(y[len2-i]-'0',0);
        for(int i=0;i<N;i++)
            R[i]=(R[i>>1]>>1)|((i&1)<<(Log-1));
        //dp得到R数组
        FFT(A0,N,1),FFT(B0,N,1);
        for(int i=0;i<N;i++)
            A0[i]=A0[i]*B0[i];
        FFT(A0,N,-1);
        for(int i=0;i<N;i++)
            res[i+1]=int(A0[i].x/N+0.5);
        for(int i=1;i<=N;i++)
            res[i+1]+=res[i]/10,res[i]%=10;
        while(N>1&&res[N]==0)
            N--;
        for(int i=N;i>=1;i--)
            putchar(res[i]+'0');
        putchar('\n');
        memset(A0,0,sizeof A0);
        memset(B0,0,sizeof B0);
        memset(res,0,sizeof res);
    }
}

后记

感谢这些大佬:

CXH大佬
十分简明易懂的FFT(快速傅里叶变换)
小学生都能看懂的FFT!!!
快速傅里叶变换(FFT)详解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FFT(快速傅里叶变换)算法 的相关文章

  • 复数如何捕获 FFT 结果中的相位、幅度和频率?

    据我了解 幅度和相位是在 fft 结果的实部和虚部中捕获的 但每个样本如何捕获相位呢 相位与时域中提供的 N 个离散样本相关吗 也就是说 如果输入样本一秒钟包含 44100 个样本 那么 FFT 的每个结果值是否代表相位的 1 44100
  • Android - 如何在录音时添加增益控制

    我为录音机应用程序工作 想添加增益控制 但我不知道该怎么做 我可以访问音频缓冲区 但我不知道如何使声音更大或更慢 我看到另一个应用程序有一个搜索栏 用于从特定范围内选择分贝 aRecorder read buffer 0 buffer le
  • 使用 fftw 和窗函数生成正确的频谱图

    对于一个项目 我需要能够从 WAV 文件生成频谱图 我读过以下应该做的事情 获取N 变换大小 个样本 Apply a window http en wikipedia org wiki Window function功能 使用样本进行快速傅
  • 使用 androids 可视化器类获取可变频率范围

    我想获取智能手机播放的声音的某些频率范围的值 以便我可以通过蓝牙将它们转发到可视化这些范围的设备 这些范围是 0 63Hz63 160赫兹160 400赫兹400 1000赫兹1000 2 500Hz2 500 6 250Hz6 250 1
  • 如何将使用 numpy.fft.rfft 的代码从 python 移植到 C++?

    我有用 python 编写的代码 它使用 numpy 计算实际输入的 FFT 正部分 我需要将此代码移植到 C import numpy as np interp 131 107 133 089 132 199 129 905 132 97
  • 为什么这个偶数函数的 FFT 不是真实的?

    因此 在 iPython 中 我运行以下命令 In 1 from pylab import In 2 x np array 4 3 2 1 0 1 2 3 4 In 3 rfft x Out 3 array 20 00000000 0 j
  • MATLAB 中的反向谱图 A La Aphex Twin

    我正在尝试将图像视为频谱图 从而在 MATLAB 中将图像转换为音频信号就像 Aphex Twin 的歌曲中那样舔窗者 http www bastwood com aphex php 不幸的是 我很难得到结果 这是我现在所拥有的 funct
  • 如何获得定义频带内的所有 fft bin 数量?

    我用的是matlab软件 对于我的问题 我有一个音频信号 我正在其上应用 STFT 我取一段 46 ms specifially chosen 我的信号消失了y audio signal 并使用FFT在上面 然后我进入下一段 直到音频信号结
  • numpy fft 对于小素数乘积的长度来说速度很快,但是有多小呢?

    我见过几个例子 表明如果输入长度是 2 3 5 7 等的乘积 那么 numpy 的 fft 实现速度很快 但是这里仍然被认为是 小 的最大素数是多少呢 请注意 scipy 的 FFT 的基数为 2 3 4 和 5 参考 https docs
  • 使用 fft 查找每个谐波的相位

    我用的是Matlab 我有一个正弦信号 X 放大器 220 频率 50 我添加了 3 个谐波 x1 gt h2 放大器 30 频率 100 相位 30 x2 gt h4 放大器 10 频率 200 相位 50 x3 gt h6 放大器 05
  • 在 Android 上查找音调

    如何从我的语音记录中找到最小 最大 平均 标准偏差音调 我使用 AudioRecord 来录制我的声音 frequency 8000 channelConfiguration AudioFormat CHANNEL CONFIGURATIO
  • fft后如何在C上均衡

    首先感谢您花时间回答 我的问题是下一个 我尝试使用 fft 快速傅立叶变换 在 C 上构建均衡器 因为现在我能够在向量 音频样本 上正确应用 fft 对其进行归一化 然后应用逆 fft 因为这里一切都好 但是当我尝试修改 fft 的结果 以
  • Python 中的帕塞瓦尔定理

    我试图掌握 Python 的 fft 功能 我偶然发现的奇怪的事情之一是帕塞瓦尔定理 http en wikipedia org wiki Parseval 27s theorem似乎不适用 因为它现在给出的差异约为 50 而它应该是 0
  • Python中基于FFT的2D卷积和相关

    scipy 或其他流行的库 中是否内置了基于 FFT 的 2D 互相关或卷积函数 有这样的函数 scipy signal correlate2d 直接方法由convolveND将 对于大数据来说很慢 scipy ndimage correl
  • 这个小波变换实现正确吗?

    我正在寻找 FFT 的替代方案来用 python 创建频谱分析仪 我听说小波变换比短时 FFT 更快并且提供更好的时间精度 我查阅了这篇维基百科文章 其中介绍了 Java 中的 Haar 小波变换实现 https en wikipedia
  • 傅里叶变换定理 matlab

    我目前正在尝试理解二维傅里叶位移定理 根据我到目前为止所了解到的情况 图像空间中的平移会导致相位差异 但不会导致频率空间中的幅度差异 我试图用一个小例子来演示这一点 但它只适用于行的移位 而不适用于列的移位 这是一个小演示 我只在这里显示幅
  • 使用FFT算法计算

    给定在平面上的点 1 0 2 0 n 0 上发现的一组 n 个粒子电荷载流子 在 i 0 点发现的粒子电荷记为 Qi 作用在粒子上的力由以下公式给出 C is a Coulomb s constant 给出一个算法来计算 Fi 对于总复杂度
  • 使用 FFT 执行音频分析

    我已经被这个问题困扰好几天了 并且浏览了几乎所有相关的 StackOverflow 页面 通过这次活动 我现在对 FFT 是什么及其工作原理有了更深入的了解 尽管如此 我在将其实现到我的应用程序中时遇到了极大的困难 简而言之 我想做的是为我
  • 通过 cuFFT 进行逆 FFT 缩放

    每当我使用 cuFFT 绘制程序获得的值并将结果与 Matlab 的结果进行比较时 我都会得到相同形状的图形 并且最大值和最小值位于相同的点 然而 cuFFT 得到的值比 Matlab 得到的值大得多 Matlab代码是 fs 1000 s
  • 帮助我理解FFT函数(Matlab)

    1 除了负频率之外 FFT 函数提供的最小频率是多少 是零吗 2 如果它为零 我们如何在对数刻度上绘制零 3 结果总是对称的 或者只是看起来是对称的 4 如果我使用abs fft y 来比较2个信号 我是否会失去一些准确性 1 除了负频率之

随机推荐

  • Unity 摄像机自适应

    脚本挂在摄像机下 using System Collections using System Collections Generic using UnityEngine 摄像机显示结果一致 拉伸 public class CameraAda
  • MySql 数据库逻辑架构

    与其他数据库相比 MySql 数据库有自己独特的地方 它的架构可以在不同的场景中应用并发挥良好的作用 主要体现在存储引擎的架构上 插件式的存储引擎架构将查询处理和其他的系统任务以及数据的存储提取相分离 这种架构的最大优点是可以根据业务和实际
  • nRF52832 — 外部中断BSP(Board Support Package)

    原文链接 http blog csdn net a369000753 article details 51312839 转载文章 若有不妥 通知后我会立即删除 首先来分析下主要的代码 cpp view plain copy brief Fu
  • 网络基础-路由器工作原理

    路由器工作原理 一 路由概述 1 路由 从源主机到目标主机的转发过程 二 路由器的工作原理 1 根据路由表转发数据 2 作用 三 路由表的形成 1 路由表 2 路由表形成 3 静态路由 4 实验过程 四 源目地址变化 1 主机A如何与主机B
  • android双栈ipv6优先级,ME60双栈场景无线业务安卓手机无法获取IPV6地址

    ME60双栈场景下 安卓手机获取IPV4地址正常 IPV6地址获取不到 PC笔记本IPV4 IPV6电脑正常 ME60版本 V800R011C10SPC100 配置脚本 dhcpv6 duid 123123 ipv6 prefix preg
  • Android 使用easeui 3.0 集成环信即时通讯 我踩过的坑

    0 关于注冊账号就不用说了 1 创建应用 获取appkey 0 创建应用 1 填写信息 2 获取appkey 2 集成 0 首先新建一个project 1 这里主要介绍使用easeui来集成环信的即时通讯功能 须要下载sdk 2 把ease
  • 期货价格的技术分析及原理

    一 基本分析与技术分析比较 一 技术分析及其特点 技术分析基于市场交易行为本身 通过分析技术数据来对期货价格走势做出预测 技术数据的表现形式主要是各种图形和指标 其实质内容主要是价格和数量 1 技术分析以三项基本假设为前提 1 包容假设 技
  • DCDC常见问题之输出带载问题

    DCDC常见问题之输出带载问题 DCDC在目前的电子产品中使用越来越常见 但是出来的问题也越来越多 下面我们将介绍DCDC输出常见的问题 该问题是一个系列 今天我们介绍的是DCDC设计时 空载下一切正常 但是带载时 输出电压出现波动等各种问
  • 【非常重要】discuz修改默认首页【自定义手机跳转页面】设置为门户页portal.php(解决设置后手机端portal跳转至forum)

    参考文章 https blog csdn net weixin 38787928 article details 87915519 注意 访问手机端发现进入门户页 portal php 后自动跳转至论坛 forum php 时 请打开 so
  • layui选项卡切换及右键的动态操作(新增、切换、删除)

    先来看个效果图 文章底部有gitee地址 要实现的效果 选项卡的新增以及切换 选项卡刷新 选项卡各种删除 删除其他 删除右侧所有 删除所有 OK 直接上代码 一些引入文件就不写了 这里只列出主要的代码 有需要的话可以去Gitee自行下载 布
  • 我开了个游戏,为什么老是被人攻击呀,怎么才能防止这个情况

    很多游戏从业者都会遇到被恶意攻击的情况 那么为什么网络上会有这种情况出现呢 一种是同行的恶意竞争 当你们开着差不多类型的游戏时 那么同行觉得你的人气比较旺 就会想办法攻击你的游戏 这样你的游戏服务器陷入宕机的话玩家就有可能流失 毕竟对玩家而
  • QT 数字转字符串自动补0或者空格,arg()的用法

    十六进制 前面自动补0 QString str QString 1 arg outChar 0xFF 2 16 QLatin1Char 0 int a 0001 十进制 前面自动补0 QString str QString 1 arg a
  • 【双指针】---反转链表

    题目 提供单向链表的头节点head 请反转链表 并返回反转后的链表 分析 同速指针 链表上两个指针 一个先出发 另一个后出发并以相同的速度跟随 通过临时指针让双指针同步前行 思路 源码 package org example pointer
  • 【UE4】蓝图结构体入门及案例

    结构体 结构体是什么 UE4中存在许多不同的变量类型 浮点 布尔 整数 字符串 等等 我们赋予变量意义 用于处理程序的运行 在需要很多意义相同的数据时 我们会应用数组的概念来储存一系列相同类型的数据 但是对于数组中的元素 其的类型是固定不变
  • CVE-2023-3836:大华智慧园区综合管理平台任意文件上传漏洞复现

    文章目录 CVE 2023 3836 大华智慧园区综合管理平台任意文件上传漏洞复现 0x01 前言 0x02 漏洞描述 0x03 影响范围 0x04 漏洞环境 0x05 漏洞复现 1 访问漏洞环境 2 构造POC 3 复现 CVE 2023
  • Java学习----习题总结

    今日习题总结如下 TCP IP分层协议栈 TCP IP协议栈参考模型分为五个层次 应用层 传输层 网络层 链路层和物理层 应用层 是网络应用程序及其应用层协议存留的层次 该层包括了所有与网络相关的高层协议 如文件传输协议 FTP 超文本传输
  • 树莓派上开热点(AP)的三种办法实践结果V2

    树莓派上开热点 AP 的三种办法实践结果 date 2021 08 02 lastmod 2021 09 19 背景 UC2 项目中树莓派大脑和子模块有两种方式连接方式 一种是采用 I2C 总线通过 Arduino 做主从 一种是走 WIF
  • Spring(二)IoC 容器

    IoC 容器 Spring 容器是 Spring 框架的核心 容器将创建对象 把它们连接在一起 配置它们 并管理他们的整个生命周期从创建到销毁 Spring 容器使用依赖注入 DI 来管理组成一个应用程序的组件 这些对象被称为 Spring
  • Arcesium面试体验

    回合 1 能力和技术回合 第一轮有20个Aptitude MCQ 20分钟 和15个技术MCQ 15分钟 分别带有 1和 0 25标记方案 MCQ涵盖了所包含的主题 DSA 操作系统 C C Java基础知识 此后 有2个编码问题 45分钟
  • FFT(快速傅里叶变换)算法

    文章目录 功能 一次FFT的功能 一次IFFT的功能 总体功能 前置技能 多项式的阶 多项式的系数表达式 多项式的点值表达式 复数 复数的基本单位 复数的运算 复平面 复根 定义 几个性质 求多项式乘积的基本步骤 FFT 递归版FFT 核心