#fft #discrete-fourier #transform #fourier #discrete #dft

realfft

针对Rust的实数到复数的正向FFT和复数到实数的逆向FFT

15个版本 (稳定)

3.3.0 2023年5月28日
3.2.0 2022年12月8日
3.1.0 2022年11月9日
3.0.0 2022年2月9日
0.2.1 2020年7月22日

#82 in 算法

Download history 10775/week @ 2024-03-14 13468/week @ 2024-03-21 13623/week @ 2024-03-28 13710/week @ 2024-04-04 13740/week @ 2024-04-11 12899/week @ 2024-04-18 13187/week @ 2024-04-25 13039/week @ 2024-05-02 11694/week @ 2024-05-09 11152/week @ 2024-05-16 11312/week @ 2024-05-23 11158/week @ 2024-05-30 11313/week @ 2024-06-06 13179/week @ 2024-06-13 12376/week @ 2024-06-20 10148/week @ 2024-06-27

48,886 每月下载量
81 个crate中使用 (24直接使用)

MIT 许可证

54KB
833

realfft

RealFFT:基于RustFFT的实数到复数的正向FFT和复数到实数的逆向FFT

这个库是对RustFFT的一个包装,它能够快速方便地对实值数据进行FFT。API设计得尽可能接近RustFFT。

使用这个库代替直接使用RustFFT,可以避免在执行FFT之前将实值数据转换为复数。如果长度是偶数,它还可以通过使用长度为原来一半的复数FFT来加快计算速度。然后,将长度为N的实值信号打包到一个长度为N/2的复数缓冲区中,并使用标准的复数到复数FFT进行转换。FFT的结果然后经过后处理,只给出复数频谱的前半部分,即一个长度为N/2+1的复数向量。

逆向FFT通过反向执行相同的步骤,将长度为N/2+1的复数频谱转换成长度为N的实值信号。

与仅将输入转换为长度为N的复数向量并使用长度为N的复数到复数FFT相比,速度提升取决于输入数据的长度。对于较长的FFT以及长度超过约1000个元素的长度,改进大约是一个因子2。对于较短的长度,差异缩小,大约在30个元素时不再有差异。

为什么要使用实数到复数的FFT?

使用复数到复数FFT

将实值信号转换为复数后,使用复数到复数FFT是一种简单的变换方法。

假设 x 是一个长度为6的实向量

x = [x0r, x1r, x2r, x3r, x4r, x5r]

我们现在将 x 转换为复数,通过添加一个值为零的虚部。使用表示复数值 xN 的符号 (xNr, xNi),这变为

x_c = [(x0r, 0), (x1r, 0), (x2r, 0), (x3r, 0), (x4r, 0), (x5r, 0)]

执行常规复数FFT,FFT(x_c)的结果是

FFT(x_c) = [(X0r, X0i), (X1r, X1i), (X2r, X2i), (X3r, X3i), (X4r, X4i), (X5r, X5i)]

但是因为我们的x_c是实值的(所有虚部都是零),其中一些就变得多余了

FFT(x_c) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, 0), (X2r, -X2i), (X1r, -X1i)]

最后两个值是X1X2的共轭复数。此外,X0iX3i为零。正如我们所见,输出包含了6个独立值,其余的都是多余的。但FFT计算这些多余值仍然需要时间。将输入数据转换为复数也需要一点时间。

如果x的长度是7,结果将是

FFT(x_c) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, X3i), (X3r, -X3i), (X2r, -X2i), (X1r, -X1i)]

结果是相似的,但这次X3i处没有零。在这种情况下,我们得到的独立值数量与开始时相同。

实数到复数

使用实数到复数FFT消除了将输入数据转换为复数的需要。它还避免了计算多余的输出值。

6个元素的结果是

RealFFT(x) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, 0)]

7个元素的答案是

RealFFT(x) = [(X0r, 0), (X1r, X1i), (X2r, X2i), (X3r, X3i)]

这是实数到复数FFT输出的数据布局,也是复杂到实数逆FFT所需的输入。

缩放

RealFFT与RustFFT的行为相匹配,并不对正向或反向FFT的输出进行归一化。要获得归一化结果,每个元素必须乘以1/sqrt(length),其中length是实值信号的长度。如果处理涉及到FFT和iFFT步骤,建议将两个归一化步骤合并为单个,通过乘以1/length

文档

完整的文档可以通过rustdoc生成。要生成并查看它,请运行

cargo doc --open

基准测试

要运行一组基准测试,比较实数到复数FFT与标准复数到复数FFT,请输入

cargo bench

运行时打印结果,并编译成包含更多详细信息的HTML报告。要查看,请在浏览器中打开target/criterion/report/index.html

示例

转换信号,然后对结果进行逆变换。

use realfft::RealFftPlanner;
use rustfft::num_complex::Complex;
use rustfft::num_traits::Zero;

let length = 256;

// make a planner
let mut real_planner = RealFftPlanner::<f64>::new();

// create a FFT
let r2c = real_planner.plan_fft_forward(length);
// make a dummy real-valued signal (filled with zeros)
let mut indata = r2c.make_input_vec();
// make a vector for storing the spectrum
let mut spectrum = r2c.make_output_vec();

// Are they the length we expect?
assert_eq!(indata.len(), length);
assert_eq!(spectrum.len(), length/2+1);

// forward transform the signal
r2c.process(&mut indata, &mut spectrum).unwrap();

// create an inverse FFT
let c2r = real_planner.plan_fft_inverse(length);

// create a vector for storing the output
let mut outdata = c2r.make_output_vec();
assert_eq!(outdata.len(), length);

// inverse transform the spectrum back to a real-valued signal
c2r.process(&mut spectrum, &mut outdata).unwrap();

版本

  • 3.3.0: 添加获取复数输入/输出长度的方法。错误修正:清除零虚部中的数值噪声。
  • 3.2.0: 允许临时缓冲区大于所需大小。
  • 3.1.0: 更新到RustFFT 6.1,支持Neon。
  • 3.0.2: 修复有关临时长度错误的令人困惑的错误。
  • 3.0.1: 更有用的错误消息,修复令人困惑的错误。
  • 3.0.0: 改进错误报告。
  • 2.0.1: 小型错误修复。
  • 2.0.0: 将RustFFT更新到6.0.0,并将num-complex更新到0.4.0。
  • 1.1.0: 添加缺失的Sync+Send。
  • 1.0.0: 新api的第一个版本。

兼容性

realfft crate与RustFFT具有相同的rustc版本要求。除AArch64平台外,所有平台的最低rustc版本为1.37。在AArch64上,最低rustc版本为1.61。

许可证:MIT

依赖项

~3MB
~57K SLoC