FFT window 导致频谱放大不均
FFT window causing unequal amplification across frequency spectrum
我正在使用 FFTW 在 C++ 中创建频谱分析仪。
对输入信号应用任何 window 函数后,输出幅度突然似乎与频率成比例。
矩形 Window
Exact-Blackman
图表以 44100 Hz 的采样频率按对数缩放。所有谐波都在相同的水平上产生,如在矩形情况下看到的那样在 0dB 处达到峰值。 Exact-Blackman window 被放大了 7.35dB 以尝试补偿处理增益。
这是我生成输入的代码table...
freq = 1378.125f;
for (int i = 0; i < FFT_LOGICAL_SIZE; i++)
{
float term = 2 * PI * i / FFT_ORDER;
for (int h = 1; freq * h < FREQ_NYQST; h+=1) // Harmonics up to Nyquist
{
fftInput[i] += sinf(freq * h * K_PI * i / K_SAMPLE_RATE); // Generate sine
fftInput[i] *= (7938 / 18608.f) - ((9240 / 18608.f) * cosf(term)) + ((1430 / 18608.f) * cosf(term * 2)); // Exact-Blackman window
}
}
fftwf_execute(fftwR2CPlan);
增大或减小 window 尺寸不会有任何变化。我也用 Hamming window 测试过,同样的问题。
这是我获取输出的代码。
float val; // Used elsewhere
for (int i = 1; i < K_FFT_COMPLEX_BINS_NOLAST; i++) // Skips the DC and Nyquist bins
{
real = fftOutput[i][0];
complex = fftOutput[i][1];
// Grabs the values and scales based on the window size
val = sqrtf(real * real + complex * complex) / FFT_LOGICAL_SIZE_OVER_2;
val *= powf(20, 7.35f / 20); // Only applied during Exact-Blackman test
}
奇怪的是,我尝试了以下尝试来平缓 Exact-Blackman 案例中的响应。这种按比例缩小导致几乎但仍不完全平坦的响应。很好,但仍然没有向我解释为什么会这样。
float x = (float)(FFT_COMPLEX_BINS - i) / FFT_COMPLEX_BINS; // Linear from 0 to 1
x = log10f((x * 9) + 1.3591409f); // Now logarithmic from 0 to 1, offset by half of Euler's constant
val = sqrt(real * real + complex * complex) / (FFT_LOGICAL_SIZE_OVER_2 / x); // Division by x added to this line
我无法重现代码,因为我手头没有库。然而,这可能是频谱泄漏的结果。 https://en.wikipedia.org/wiki/Spectral_leakage
这是window函数和采样的必然性。如果您查看该文章的权衡部分,window 的类型可以适应广泛的频率或专注于特定频率。由于您的信号频率正在增加,因此目标外部的较低频率信号可能更容易受到频谱泄漏的影响。
可能是一个错误。您似乎在每个样本中多次应用 window 函数。任何 windowing 都应该从您的输入合成循环中删除,并仅在 FFT 之前应用于输入向量一次。
我正在使用 FFTW 在 C++ 中创建频谱分析仪。
对输入信号应用任何 window 函数后,输出幅度突然似乎与频率成比例。
矩形 Window
Exact-Blackman
图表以 44100 Hz 的采样频率按对数缩放。所有谐波都在相同的水平上产生,如在矩形情况下看到的那样在 0dB 处达到峰值。 Exact-Blackman window 被放大了 7.35dB 以尝试补偿处理增益。
这是我生成输入的代码table...
freq = 1378.125f;
for (int i = 0; i < FFT_LOGICAL_SIZE; i++)
{
float term = 2 * PI * i / FFT_ORDER;
for (int h = 1; freq * h < FREQ_NYQST; h+=1) // Harmonics up to Nyquist
{
fftInput[i] += sinf(freq * h * K_PI * i / K_SAMPLE_RATE); // Generate sine
fftInput[i] *= (7938 / 18608.f) - ((9240 / 18608.f) * cosf(term)) + ((1430 / 18608.f) * cosf(term * 2)); // Exact-Blackman window
}
}
fftwf_execute(fftwR2CPlan);
增大或减小 window 尺寸不会有任何变化。我也用 Hamming window 测试过,同样的问题。
这是我获取输出的代码。
float val; // Used elsewhere
for (int i = 1; i < K_FFT_COMPLEX_BINS_NOLAST; i++) // Skips the DC and Nyquist bins
{
real = fftOutput[i][0];
complex = fftOutput[i][1];
// Grabs the values and scales based on the window size
val = sqrtf(real * real + complex * complex) / FFT_LOGICAL_SIZE_OVER_2;
val *= powf(20, 7.35f / 20); // Only applied during Exact-Blackman test
}
奇怪的是,我尝试了以下尝试来平缓 Exact-Blackman 案例中的响应。这种按比例缩小导致几乎但仍不完全平坦的响应。很好,但仍然没有向我解释为什么会这样。
float x = (float)(FFT_COMPLEX_BINS - i) / FFT_COMPLEX_BINS; // Linear from 0 to 1
x = log10f((x * 9) + 1.3591409f); // Now logarithmic from 0 to 1, offset by half of Euler's constant
val = sqrt(real * real + complex * complex) / (FFT_LOGICAL_SIZE_OVER_2 / x); // Division by x added to this line
我无法重现代码,因为我手头没有库。然而,这可能是频谱泄漏的结果。 https://en.wikipedia.org/wiki/Spectral_leakage
这是window函数和采样的必然性。如果您查看该文章的权衡部分,window 的类型可以适应广泛的频率或专注于特定频率。由于您的信号频率正在增加,因此目标外部的较低频率信号可能更容易受到频谱泄漏的影响。
可能是一个错误。您似乎在每个样本中多次应用 window 函数。任何 windowing 都应该从您的输入合成循环中删除,并仅在 FFT 之前应用于输入向量一次。