存储具有最少数据量的 FFT

信息处理 fft 离散信号 傅里叶变换
2022-01-24 12:01:29

我有一个长度为 1024 的数组x(存储为 16 位整数,例如np.int16在 numpy/python 中命名),即x 的大小为 1024*2 = 2048 字节。

备注:x 来自一个音频 .wav 文件,存储为 16 位整数,因为它很常见。但也很常见将其解释为浮点数组,其值在中:)[1,+1] x = x * 1.0 / 2^16 _

当我接受fft(x)时,由于输入是真实的,因此存在一些对称性,我只需要存储数组fft(x)的一半,这通常也称为rfft(x)真正的 fft

  • 这意味着,通过取fft,我将 1024 个实数转换为 512 个复数(即可以再次被视为 1024 个实数):从数学的角度来看,我们拥有相同数量的数据:

    1024 real coefficients -- rfft --> 1024 real coefficients

但从编程的角度来看,是否可以无损*且不压缩地存储1024 个类型元素(使用 2048 字节)fft的数组,最大 2048 字节?int16

fft如果不是,存储这样一个数组所需的最小字节数是多少?

备注 (*) : 无损我的意思是原始x可以稍后恢复

3个回答

通常,量化 FFT 结果是一个有损过程。鉴于 FFT 旋转因子是超越函数,任何有限的存储大小都会导致添加一些量化噪声;并且随着生成的格式的位大小减小,噪声会增加。对于极其稀疏的 FFT 结果,可以压缩这些结果,但这些在统计上是非常罕见的情况。

好的,我可以为您提供(几乎)答案:

如果您使用基于提升的实现具有量化系数的复旋转因子乘法,则执行乘法后字长将增加三倍于系数字长。因此,直接评估将给出初始数据字长加上三倍的系数字长加上 10(即 1024 的两个对数)。这是使用直接计算存储 DFT 计算的确切结果所需要的。如果您改为使用 FFT 算法,您将看到最多九个旋转因子阶段,每个阶段添加三倍的系数字长位数。

我想这些数字实际上都不是您想要的,因为您可能不想编写自己的 DFT/FFT。此外,有了这些数字,“你需要 DFT 做什么?”的问题。和“你需要多好的 DFT 近似值?” 迅速出现。

这不完全是一个答案(我希望它会很快成为它),而是基于经验的结果:

import numpy as np
from scipy.io.wavfile import read, write
from scipy.fftpack import rfft, irfft

(fs, x) = read('nowomannocry_16bit_mono.wav')

y = rfft(x)
M = max(abs(y))
y *= 1.0 * (2**23-1) / M               # mapped into [-2^23, 2^23 -1]
y = np.round(y)
y = np.int32(y)   # here we store the fft by using the full width of 24 bits 

z = irfft(y) * M / (2**23-1)
z = np.round(z)
z = np.int16(z)
print z - x, max(abs(z-x))
# [0 0 0 ..., 0 0 0] 0

根据这个小测试(在Bob Marley 的 No woman no cry, 16 bit, mono上完成),24 位似乎足以存储原始信号的 FFT,这样原始信号可以通过以下方式恢复RFFT。

我尝试了 16、20、22 位,但还不够。

这些只是经验,但是可以在这个方向上证明什么吗?