【发布时间】:2014-02-12 12:34:02
【问题描述】:
对于一个项目,我需要能够从 .WAV 文件生成频谱图。我已经阅读了以下应该做的:
- 获取 N 个(变换大小)样本
- 应用window 函数
- 使用样本进行快速傅里叶变换
- 标准化输出
- 生成频谱图
在下图中,您可以看到两个使用hanning 窗口函数的 10000 Hz 正弦波的频谱图。在左边你会看到由audacity 生成的频谱图,在右边是我的版本。如您所见,我的版本有更多的线条/噪音。这是在不同的垃圾箱中泄漏吗?我将如何获得像大胆生成的清晰图像。我应该做一些后期处理吗?我还没有做任何规范化,因为不完全理解如何去做。
更新
我发现 this 教程解释了如何在 C++ 中生成频谱图。我编译了源代码,看看我能找到什么差异。
说实话,我的数学很生疏,所以我不确定标准化在这里做了什么:
for(i = 0; i < half; i++){
out[i][0] *= (2./transform_size);
out[i][6] *= (2./transform_size);
processed[i] = out[i][0]*out[i][0] + out[i][7]*out[i][8];
//sets values between 0 and 1?
processed[i] =10. * (log (processed[i] + 1e-6)/log(10)) /-60.;
}
完成此操作后,我得到了这张图片(顺便说一下,我已经反转了颜色):
然后,我查看了我的声音库和教程提供的输入样本的差异。我的要高得多,所以我手动标准化是将它除以因子 32767.9。然后我去这张我认为看起来还不错的图像。但除以这个数字似乎是错误的。我希望看到不同的解决方案。
这里是完整的相关源代码。
void Spectrogram::process(){
int i;
int transform_size = 1024;
int half = transform_size/2;
int step_size = transform_size/2;
double in[transform_size];
double processed[half];
fftw_complex *out;
fftw_plan p;
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * transform_size);
for(int x=0; x < wavFile->getSamples()/step_size; x++){
int j = 0;
for(i = step_size*x; i < (x * step_size) + transform_size - 1; i++, j++){
in[j] = wavFile->getSample(i)/32767.9;
}
//apply window function
for(i = 0; i < transform_size; i++){
in[i] *= windowHanning(i, transform_size);
// in[i] *= windowBlackmanHarris(i, transform_size);
}
p = fftw_plan_dft_r2c_1d(transform_size, in, out, FFTW_ESTIMATE);
fftw_execute(p); /* repeat as needed */
for(i = 0; i < half; i++){
out[i][0] *= (2./transform_size);
out[i][11] *= (2./transform_size);
processed[i] = out[i][0]*out[i][0] + out[i][12]*out[i][13];
processed[i] =10. * (log (processed[i] + 1e-6)/log(10)) /-60.;
}
for (i = 0; i < half; i++){
if(processed[i] > 0.99)
processed[i] = 1;
In->setPixel(x,(half-1)-i,processed[i]*255);
}
}
fftw_destroy_plan(p);
fftw_free(out);
}
【问题讨论】:
-
你可以检查零频率,数组
out[0]中的第一项。它代表信号的平均值。如果它与您期望的值不同,那可能是因为 fftw 定义。它可以乘以transform_size。 -
@francis 这不会影响整个频谱图吧?只有零频率
-
你看过大胆的源代码吗?如果我没记错的话,它很有条理。
-
@Boedy:FFT 是线性的:时域中的乘数导致频域中完全相同的乘数。 0 bin 是直流偏移。 (+ 而不是 *)
-
顺便说一句,看看 Audacity Analyze Spectrum 视图,它显示了几个不同窗口函数的效果。
标签: c++ fft fftw spectrogram