将FFT转换为PCM



我有一些FFT数据,257维,每10毫秒,121帧,即1.21秒。我想第一个维度可能是别的东西剩下的是FFT系数,我猜。这可能只是光谱数据。从对FFT数据的评论来看,sqrt10和均值方差归一化可能已经应用于它。

从那里,我想计算回一些44.1 Hz的PCM信号,这样我就可以播放声音。我在这里用更数学的方式问了同样的问题,但也许StackOverflow是一个更好的地方,因为我实际上想实现这个。我也问了同样的问题关于这里的理论在DSP SE。

我该怎么做呢?也许我需要一些更多的信息(我必须以某种方式找到)-哪一个?也许这些缺失的信息可以被智能地猜出来?

这个问题既是一个理论问题,也是一个实践问题。我想实现是微不足道的。但是用某种语言举一个具体的例子会很好地帮助理解这个理论。也许c++ + FFTW?我跳过了FFTW文档,但我无法理解所有的术语和一些背景,例如在这里。为什么从复到实,或者相反,我只想从实到实。那些REDFT是什么?什么是DCT, DFT, DST?FFTW_HC2R吗?

我读取所有FFT数据,即121 * 257浮点数,到一个向量freq_bins

std::vector<float32_t> freq_bins; // FFT data
int freq_bins_count = 257;
size_t len = 121;
std::vector<float32_t> pcm; // output, PCM data
int N = freq_bins_count;
std::vector<double> out(N), orig_in(N);
// inspiration: https://stackoverflow.com/questions/2459295/invertible-stft-and-istft-in-python/6891772#6891772
for(int f = 0; f < len; ++f) {
    size_t pos = freq_bins_count * f;
    for(int i = 0; i < N; ++i)
        out[i] = pow(freq_bins[pos + i] + offset, 10);  // fft was sqrt10 + mvn
    fftw_plan q = fftw_plan_r2r_1d(N, &out[0], &orig_in[0], FFTW_REDFT00, FFTW_ESTIMATE);
    fftw_execute(q);
    fftw_destroy_plan(q);
    // naive overlap-and-add
    auto start_frame = size_t(f * dt * sampleRate);
    for(int i = 0; i < N; ++i) {
        sample_t frame = orig_in[i] * scale / (2 * (N - 1));
        size_t idx = start_frame + i;
        while(idx >= pcm.size())
            pcm.push_back(0);
        pcm[idx] += frame;
    }
}

但这是错误的,我想。我只是把垃圾扔出去。

可能与这个问题有关。或者这个。

如果你所拥有的数据是真实的,那么你所拥有的数据很可能是谱图数据,如果你接收的数据是复杂的,那么你最有可能拥有原始的短时间傅里叶变换(STFT)数据(参见这篇文章上的图表,看看STFT/谱图数据是如何产生的)。频谱图数据是通过取STFT数据的幅度平方产生的,因此是不可逆的,因为音频信号中的所有相位信息都丢失了,但原始STFT数据是可逆的,所以如果这就是你所拥有的,那么你可能想寻找一个执行逆STFT函数的库并尝试使用它。

至于数据中的FFT维度代表什么问题,我认为您每10ms接收的257个数据点是在STFT过程中使用的512点FFT的结果。第一个样本是0Hz频率,其余的256个数据点是FFT频谱的一半(FFT数据的另一半已经被丢弃,因为FFT的输入是实的,所以FFT数据的一半只是另一半的复共轭)。

除此之外,我想指出的是,仅仅因为你每10ms接收FFT数据121次并不意味着音频信号是1.21秒。STFT通常是通过使用重叠窗口产生的,所以你的音频信号可能短于1.21秒。

你只需要把这些数据进行傅里叶反变换。所有FFT库都提供向前和向后转换函数。

最新更新