FFT结果的大小取决于波频率?
我对 FFT 得到的结果感到困惑,希望得到任何帮助。
我正在使用 FFTW 3.2.2,但使用其他 FFT 实现(在 Java 中)也得到了类似的结果。当我对正弦波进行 FFT 时,结果的缩放取决于波的频率 (Hz),特别是它是否接近整数。当频率接近整数时,结果值会缩放得非常小;而当频率在整数之间时,结果值会大几个数量级。 该图显示了 FFT 结果中对应于的尖峰幅度波的频率,对于不同的频率。这是对的吗?
我查了一下FFT的逆FFT等于原始正弦波乘以样本数,确实如此。 FFT 的形状似乎也是正确的。
如果我分析单个正弦波,情况也不会那么糟糕,因为我可以在 FFT 中寻找尖峰,而不管其高度如何。问题是我想分析正弦波的总和。如果我分析 440 Hz 和 523.25 Hz 的正弦波之和,则只会显示 523.25 Hz 的尖峰。另一个的尖峰非常小,看起来就像噪音。一定有某种方法可以实现这一点,因为在 Matlab 中它确实有效——我在两个频率上都得到了类似大小的尖峰。如何更改下面的代码以均衡不同频率的缩放?
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <fftw3.h>
#include <cstdio>
using namespace std;
const double PI = 3.141592;
/* Samples from 1-second sine wave with given frequency (Hz) */
void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor);
int main(int argc, char** argv) {
/* Args: frequency (Hz), samplesPerSecond, ampFactor */
if (argc != 4) return -1;
double frequency = atof(argv[1]);
int samplesPerSecond = atoi(argv[2]);
double ampFactor = atof(argv[3]);
/* Init FFT input and output arrays. */
double * wave = new double[samplesPerSecond];
sineWave(wave, frequency, samplesPerSecond, ampFactor);
double * fftHalfComplex = new double[samplesPerSecond];
int fftLen = samplesPerSecond/2 + 1;
double * fft = new double[fftLen];
double * ifft = new double[samplesPerSecond];
/* Do the FFT. */
fftw_plan plan = fftw_plan_r2r_1d(samplesPerSecond, wave, fftHalfComplex, FFTW_R2HC, FFTW_ESTIMATE);
fftw_execute(plan);
memcpy(fft, fftHalfComplex, sizeof(double) * fftLen);
fftw_destroy_plan(plan);
/* Do the IFFT. */
fftw_plan iplan = fftw_plan_r2r_1d(samplesPerSecond, fftHalfComplex, ifft, FFTW_HC2R, FFTW_ESTIMATE);
fftw_execute(iplan);
fftw_destroy_plan(iplan);
printf("%s,%s,%s", argv[1], argv[2], argv[3]);
for (int i = 0; i < samplesPerSecond; i++) {
printf("\t%.6f", wave[i]);
}
printf("\n");
printf("%s,%s,%s", argv[1], argv[2], argv[3]);
for (int i = 0; i < fftLen; i++) {
printf("\t%.9f", fft[i]);
}
printf("\n");
printf("\n");
printf("%s,%s,%s", argv[1], argv[2], argv[3]);
for (int i = 0; i < samplesPerSecond; i++) {
printf("\t%.6f (%.6f)", ifft[i], samplesPerSecond * wave[i]); // actual and expected result
}
delete[] wave;
delete[] fftHalfComplex;
delete[] fft;
delete[] ifft;
}
void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor) {
for (int i = 0; i < samplesPerSecond; i++) {
double time = i / (double) samplesPerSecond;
a[i] = ampFactor * sin(2 * PI * frequency * time);
}
}
I'm baffled by the results I'm getting from FFT and would appreciate any help.
I'm using FFTW 3.2.2 but have gotten similar results with other FFT implementations (in Java). When I take the FFT of a sine wave, the scaling of the result depends on the frequency (Hz) of the wave--specifically, whether it's close to a whole number or not. The resulting values are scaled really small when the frequency is near a whole number, and they're orders of magnitude larger when the frequency is in between whole numbers. This graph shows the magnitude of the spike in the FFT result corresponding to the wave's frequency, for different frequencies. Is this right??
I checked that the inverse FFT of the FFT is equal to the original sine wave times the number of samples, and it is. The shape of the FFT also seems to be correct.
It wouldn't be so bad if I were analyzing individual sine waves, because I could just look for the spike in the FFT regardless of its height. The problem is that I want to analyze sums of sine waves. If I'm analyzing a sum of sine waves at, say, 440 Hz and 523.25 Hz, then only the spike for the one at 523.25 Hz shows up. The spike for the other is so tiny that it just looks like noise. There must be some way to make this work because in Matlab it does work-- I get similar-sized spikes at both frequencies. How can I change the code below to equalize the scaling for different frequencies?
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <fftw3.h>
#include <cstdio>
using namespace std;
const double PI = 3.141592;
/* Samples from 1-second sine wave with given frequency (Hz) */
void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor);
int main(int argc, char** argv) {
/* Args: frequency (Hz), samplesPerSecond, ampFactor */
if (argc != 4) return -1;
double frequency = atof(argv[1]);
int samplesPerSecond = atoi(argv[2]);
double ampFactor = atof(argv[3]);
/* Init FFT input and output arrays. */
double * wave = new double[samplesPerSecond];
sineWave(wave, frequency, samplesPerSecond, ampFactor);
double * fftHalfComplex = new double[samplesPerSecond];
int fftLen = samplesPerSecond/2 + 1;
double * fft = new double[fftLen];
double * ifft = new double[samplesPerSecond];
/* Do the FFT. */
fftw_plan plan = fftw_plan_r2r_1d(samplesPerSecond, wave, fftHalfComplex, FFTW_R2HC, FFTW_ESTIMATE);
fftw_execute(plan);
memcpy(fft, fftHalfComplex, sizeof(double) * fftLen);
fftw_destroy_plan(plan);
/* Do the IFFT. */
fftw_plan iplan = fftw_plan_r2r_1d(samplesPerSecond, fftHalfComplex, ifft, FFTW_HC2R, FFTW_ESTIMATE);
fftw_execute(iplan);
fftw_destroy_plan(iplan);
printf("%s,%s,%s", argv[1], argv[2], argv[3]);
for (int i = 0; i < samplesPerSecond; i++) {
printf("\t%.6f", wave[i]);
}
printf("\n");
printf("%s,%s,%s", argv[1], argv[2], argv[3]);
for (int i = 0; i < fftLen; i++) {
printf("\t%.9f", fft[i]);
}
printf("\n");
printf("\n");
printf("%s,%s,%s", argv[1], argv[2], argv[3]);
for (int i = 0; i < samplesPerSecond; i++) {
printf("\t%.6f (%.6f)", ifft[i], samplesPerSecond * wave[i]); // actual and expected result
}
delete[] wave;
delete[] fftHalfComplex;
delete[] fft;
delete[] ifft;
}
void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor) {
for (int i = 0; i < samplesPerSecond; i++) {
double time = i / (double) samplesPerSecond;
a[i] = ampFactor * sin(2 * PI * frequency * time);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是因为快速傅里叶变换假设输入是周期性的并且无限重复。如果您有非整数个正弦波,并且重复此波形,则它不是完美的正弦波。这会导致 FFT 结果受到“频谱泄漏”的影响。
请查看窗口函数。这些会衰减开始和结束时的输入,从而减少频谱泄漏。
ps:如果您想获得基波附近的精确频率内容,请捕获大量波浪周期,并且不需要每个周期捕获太多点(每个周期 32 或 64 个点可能就足够了)。如果您想获得高次谐波的精确频率内容,请捕获较少数量的周期,并在每个周期捕获更多点。
That's because a Fast Fourier Transform assumes the input is periodic and is repeated infinitely. If you have a nonintegral number of sine waves, and you repeat this waveform, it is not a perfect sine wave. This causes an FFT result that suffers from "spectral leakage"
Look into window functions. These attenuate the input at the beginning and end, so that spectral leakage is diminished.
p.s.: if you want to get precise frequency content around the fundamental, capture lots of wave cycles and you don't need to capture too many points per cycle (32 or 64 points per cycle is probably plenty). If you want to get precise frequency content at higher harmonics, capture a smaller number of cycles, and more points per cycle.
我只能建议你看看 GNU Radio 代码。您可能特别感兴趣的文件是 usrp_fft.py。
I can only recommend that you look at GNU Radio code. The file that could be of particular interest to you is usrp_fft.py.