惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
博客园 - 【当耐特】
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
小众软件
小众软件
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 三生石上(FineUI控件)
B
Blog
有赞技术团队
有赞技术团队
J
Java Code Geeks
云风的 BLOG
云风的 BLOG
Recent Announcements
Recent Announcements
Jina AI
Jina AI
Vercel News
Vercel News
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
F
Fortinet All Blogs
The Cloudflare Blog
V
V2EX
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
腾讯CDC

物灵

A non-gamer’s view on games ◎物灵 I am a ruin aborigine ◎ 物灵 The spreadsheet-makers ◎物灵 وِسَ ڠ دَاِقࣨ؟ ◎物灵 领有和非领有的 C++ range ◎物灵 Do not get gentle into your CS major ◎物灵 ཡིའུ་ཀང་ལག་ ◎ 物灵 슈홋(守候) 2038넌(年) ◎物灵 Buku-name de Mini kon Sina-litera ◎物灵 ‘My Path’ after twenty years ◎物灵 My linguistic history ◎物灵 A slice of Bash programmable completion ◎物灵 Enhypen Alphabet ◎物灵 GNU 四十年 ◎物灵 ‘If need be, I will leave w/o looking back…’ ◎物灵 omekapo, Lánzhōu ⟲物灵 说说选登 ◎ 物灵 Back in old Ruyqiuan ◎物灵 linluwi lili li pona a! ⟲物灵 「挺」的中古三字 ◎物灵 最后一天 ◎物灵 基于 RFID 及智能终端的户外团队运动系统 ◎物灵 Which character for inbound passengers? ◎物灵 Kokanu in lika Hanci ◎物灵 Number of shapes of Rubik’s snake ◎物灵 دࣱخُاْ ۋاًخُوَاتࣨ ◎物灵 Childhood ◎物灵 个人视觉识别系统(辛丑) ◎物灵 ((报告 书) = (书 (报告 书)) ◎物灵 Speech before final examination ◎物灵
离散傅里叶变换 ◎物灵
Unknown · 2018-08-07 · via 物灵

考虑傅里叶级数

` f(x)=sum _ (n=-oo)^(+oo) a_n exp("j"nx) = sum _ (n=-oo)^(+oo) a_n (cos nx+"j"sin nx) `

其中

` int _ -pi ^ pi f(x) exp(-"j"mx) "d"x = int _ -pi ^ pi sum _ (n=-oo)^(+oo) a_n exp("j"(n-m)x) = sum _ (n=-oo)^(+oo) a_n int _ -pi ^ pi exp("j"(n-m)x) = 2pi sum _ (n=-oo)^(+oo) a_n [n=m] = 2pi a_m `

` a_m=1/2pi int _ -pi ^ pi f(x) exp(-"j"mx) "d"x `

在任意周期下可得

` f(x)=sum _ (n=-oo)^(+oo) a_n exp((2pi)/l "j"nx) `
` a_m=1/l int _ -l ^ l f(x) exp(-(2pi)/l "j"mx) "d"x `

这不只是假设的权宜。由傅里叶级数我们得到一列离散的强度 `a_n`。为使提取的强度不依赖周期,在 `l->oo` 时,有以 `k=n/l` 为参数的函数。在上式作这个代换,可以写出

` f(x)=sum _ (n=-oo)^(+oo) int _ -oo ^ (+oo) F(k) exp(2pi "j"kx) "d"x `
` F(k)= int _ -oo ^ (+oo) f(x) exp(-2pi "j"kx) "d"x `

`F(x)`1 称为 `f(x)` 的傅里叶变换,与之相对的是傅里叶逆变换。

傅里叶变换刻画了连续函数 f。对离散信号 `x_N`,表示为 `f(kT)`,则

` X_n=F(n/N T) = int _ -oo ^ (+oo) f(x) exp(-2pi n"j"Tx) "d"x = sum _ (k=0) ^ (N-1) x_k exp(-2pi "j"kn/N) `

` X_n = sum _ (k=0) ^ (N-1) x_k exp(-2pi "j"kn/N) `

与之相对的是逆变换

` x_n = 1/N sum _ (k=0) ^ (N-1) X_k exp(2pi "j"kn/N) `

因此,朴素实现在 O(N²) 变换全序列。

快速傅里叶变换(FFT)在 O(N lg N) 变换全序列,其基于下述分解:当 N 是 2 的幂时

` sum _ (k=0) ^ (N-1) x_k exp(-2pi "j"kn/N) = sum _ (k=0) ^ (N/2-1) x_(2k) exp(-2pi "j"kn/(N/2)) + exp(-2pi "j"k/N) sum _ (k=0) ^ (N/2-1) x_(1+2k) exp(-2pi "j"kn/(N/2)) `

够了么?不!注意还有一个参数 n!在 `n > N/2` 时子问题的 k 超范围,我们增加下式保证分后范围,其中负号由于 `-1=exp(-pi "j")`:

` sum _ (k=0) ^ (N-1) x_k exp(-2pi "j"k(n+N/2)/N) = sum _ (k=0) ^ (N/2-1) x_(2k) exp(-2pi "j"kn/(N/2)) - exp(-2pi "j"k/N) sum _ (k=0) ^ (N/2-1) x_(1+2k) exp(-2pi "j"kn/(N/2)) `

上两式记作 (†) 式。注意该式左侧关于前后,右侧关于奇偶。因此,二基数 FFT 可用以下递归过程表示:

void fft_recursive(complex a[], complex res[], int al, int ar, int is) {
  int mid = al + ar >> 1, len = ar - al >> 1;
  std::copy(a + al, a + ar, res + al); if (ar - al == 1) return;
  for (int i = 0; i < len; ++i) a[al + i] = res[al + lc(i)], a[(al + ar) / 2 + i] = res[al + rc(i)];
  fft_recursive(a, res, al, mid, is), fft_recursive(a, res, mid, ar, is);
  for (int i = 0; i < ar - mid; ++i) res[mid + i] *= exp(2 * PI * I * is * i / len); // (*)
  for (int i = 0; i < len; ++i) { complex b = res[al + i], c = res[mid + i]; res[al + i] += c, res[mid + i] = b - c; }}

其中 (*) 式表示项 `exp(-2pi "j"k/N)`,末行表示 (†) 式。

递归过程计 lg N 层,各层差别在处理顺序,即奇偶到前后的重排。要之,(*) 以原奇偶选中,(†) 式则是相邻二者的配对。好在递归过后自 (*) 开始不必重排,递归中的重排发生于块内,未影响 res[al + i]res[mid + i] 的先后。因此我们只需起头便移到上述 a[] 的末态。

来段没营养的废话。我们这样考虑推移过程,对节长 l,该步选取 l 所在位为 1 者长为 l 的块依次为前、后、前、后……且序号低于(含)l 的部分(模 2l 馀数)循环移位,即抽出奇偶,放到 l 处。由于 l 从高到低,得到的是原序号的位翻转。恰好处在原序号位翻转的项亦交换至原序号。

int revbin_gen(int r, int n) {
  do if (n & (r ^= n)) return r; while (n >>= 1); }
void revbin_permute(complex a[], int n) {
  for (int i = 0, r = 0; i < n; ++i, r = revbin_gen(r, n / 2)) if (r > i) swap(a[i], a[r]); }
void fft(complex a[], int n, int ls) {
  revbin_permute(a, n);
  for (int l = 1; l < n; l <<= 1) for (int j = 0; j < l; ++j)
    for (int i = 0, z = exp(PI * I * is * j / l); i < n; i += l) {
      complex b = a[i + j], c = z * a[i + j + l]; a[i + j] = b + c, a[i + j + l] = b - c; }}