对于一个项目,我需要能够从 .WAV 文件生成频谱图。我读过以下应该做的事情:
- 获取N(变换大小)个样本
- Apply a window http://en.wikipedia.org/wiki/Window_function功能
- 使用样本进行快速傅里叶变换
- 标准化输出
- 生成频谱图
在下图中,您可以看到两个 10000 Hz 正弦波的频谱图,均使用hanning http://en.wikipedia.org/wiki/Window_function#Hann_.28Hanning.29_window窗函数。在左侧您可以看到由以下命令生成的频谱图audacity http://audacity.sourceforge.net/右边是我的版本。正如你所看到的,我的版本有更多的线条/噪音。是否泄漏在不同的垃圾箱中?我怎样才能获得像大胆产生的清晰图像。我应该做一些后期处理吗?我还没有进行任何标准化,因为不完全了解如何做到这一点。
update
I found this http://www.gemmantics.com/spectrograms-in-c-with-libav-ffmpeg-libpng-and-sphinx/教程解释如何用 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);
}