当前位置:首页 > JavaScript

fft js实现

2026-04-05 05:18:04JavaScript

FFT(快速傅里叶变换)的 JavaScript 实现

快速傅里叶变换(FFT)是一种高效计算离散傅里叶变换(DFT)的算法。以下是基于 Cooley-Tukey 算法的递归实现,适用于长度为 2 的幂次的输入。

递归实现

function fft(signal) {
    const N = signal.length;
    if (N === 1) return signal;

    const even = fft(signal.filter((_, i) => i % 2 === 0));
    const odd = fft(signal.filter((_, i) => i % 2 === 1));
    const result = new Array(N).fill(0).map((_, k) => {
        const angle = -2 * Math.PI * k / N;
        const exp = { re: Math.cos(angle), im: Math.sin(angle) };
        const term = {
            re: exp.re * odd[k % (N/2)].re - exp.im * odd[k % (N/2)].im,
            im: exp.re * odd[k % (N/2)].im + exp.im * odd[k % (N/2)].re
        };
        return {
            re: even[k % (N/2)].re + term.re,
            im: even[k % (N/2)].im + term.im
        };
    });
    return result;
}

非递归优化实现

递归实现虽然直观,但性能较差。以下是基于迭代的非递归实现:

fft js实现

function fftIterative(input) {
    const N = input.length;
    const log2N = Math.log2(N);
    const output = input.map((val, i) => ({ re: val, im: 0 }));

    for (let s = 1; s <= log2N; s++) {
        const m = 1 << s;
        const wm = { 
            re: Math.cos(-2 * Math.PI / m), 
            im: Math.sin(-2 * Math.PI / m) 
        };
        for (let k = 0; k < N; k += m) {
            let w = { re: 1, im: 0 };
            for (let j = 0; j < m / 2; j++) {
                const t = {
                    re: w.re * output[k + j + m/2].re - w.im * output[k + j + m/2].im,
                    im: w.re * output[k + j + m/2].im + w.im * output[k + j + m/2].re
                };
                const u = output[k + j];
                output[k + j] = { re: u.re + t.re, im: u.im + t.im };
                output[k + j + m/2] = { re: u.re - t.re, im: u.im - t.im };
                w = {
                    re: w.re * wm.re - w.im * wm.im,
                    im: w.re * wm.im + w.im * wm.re
                };
            }
        }
    }
    return output;
}

使用示例

const signal = [1, 1, 1, 1, 0, 0, 0, 0]; // 长度为 8 的示例信号(2^3)
const spectrum = fftIterative(signal);
console.log(spectrum.map(c => `${c.re.toFixed(2)} + ${c.im.toFixed(2)}i`));

注意事项

  • 输入信号长度必须是 2 的幂次(如 2, 4, 8, 16 等),否则需要补零。
  • 输出结果为复数数组,包含实部(re)和虚部(im)。
  • 如需逆变换(IFFT),可将旋转因子的角度符号取反,并最终除以 N。

性能优化建议

  • 预处理旋转因子(twiddle factors)以减少重复计算。
  • 使用 TypedArray(如 Float32Array)替代普通数组提升性能。
  • 对于大规模数据,考虑 WebAssembly 或 GPU 加速(如 WebGL)。

标签: fftjs
分享给朋友:

相关文章

js实现跳转

js实现跳转

使用 window.location 跳转 通过修改 window.location.href 实现页面跳转,这是最常用的方法。 window.location.href = 'https://…

js实现延迟

js实现延迟

实现延迟的方法 在JavaScript中,实现延迟操作有多种方式,以下是几种常见的方法: 使用setTimeout函数 setTimeout是JavaScript中最常用的延迟执行方法。它接受一个回…

js实现百叶窗

js实现百叶窗

使用CSS和JavaScript实现百叶窗效果 通过CSS动画和JavaScript事件监听可以实现百叶窗效果。核心思路是将内容区域分割为多个条状元素,通过控制它们的展开/折叠状态来模拟百叶窗。 &…

js实现变形

js实现变形

使用 CSS 和 JavaScript 实现元素变形 在 JavaScript 中实现变形效果通常结合 CSS 的 transform 属性,通过动态修改该属性实现元素的旋转、缩放、倾斜或平移。 基…

js实现dh

js实现dh

JavaScript 实现 DH(Diffie-Hellman)密钥交换 Diffie-Hellman(DH)密钥交换是一种安全协议,允许双方在不安全的通信信道上建立一个共享密钥。以下是如何在 Jav…

js手势实现

js手势实现

手势识别实现方法 在JavaScript中实现手势识别通常涉及监听触摸事件(touchstart、touchmove、touchend)或鼠标事件(mousedown、mousemove、mouseu…