首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >纯正弦FFT更精确的频率

纯正弦FFT更精确的频率
EN

Stack Overflow用户
提问于 2014-01-26 15:25:24
回答 3查看 1.1K关注 0票数 0

我目前正在使用这里的快速傅立叶变换代码:https://github.com/syedhali/EZAudio/tree/master/EZAudioExamples/iOS/EZAudioFFTExample

以下是两个相关方法的代码:

代码语言:javascript
运行
复制
-(void)createFFTWithBufferSize:(float)bufferSize withAudioData:(float*)data {

  // Setup the length
  _log2n = log2f(bufferSize);

  // Calculate the weights array. This is a one-off operation.
  _FFTSetup = vDSP_create_fftsetup(_log2n, FFT_RADIX2);

  // For an FFT, numSamples must be a power of 2, i.e. is always even
  int nOver2 = bufferSize/2;

  // Populate *window with the values for a hamming window function
  float *window = (float *)malloc(sizeof(float)*bufferSize);
  vDSP_hamm_window(window, bufferSize, 0);
  // Window the samples
  vDSP_vmul(data, 1, window, 1, data, 1, bufferSize);
  free(window);

  // Define complex buffer
 _A.realp = (float *) malloc(nOver2*sizeof(float));
 _A.imagp = (float *) malloc(nOver2*sizeof(float));

}

-(void)updateFFTWithBufferSize:(float)bufferSize withAudioData:(float*)data {

  // For an FFT, numSamples must be a power of 2, i.e. is always even
  int nOver2 = bufferSize/2;

  // Pack samples:
  // C(re) -> A[n], C(im) -> A[n+1]
  vDSP_ctoz((COMPLEX*)data, 2, &_A, 1, nOver2);

  // Perform a forward FFT using fftSetup and A
  // Results are returned in A
  vDSP_fft_zrip(_FFTSetup, &_A, 1, _log2n, FFT_FORWARD);

  // Convert COMPLEX_SPLIT A result to magnitudes
  float amp[nOver2];
  float maxMag = 0;

  for(int i=0; i<nOver2; i++) {
    // Calculate the magnitude
    float mag = _A.realp[i]*_A.realp[i]+_A.imagp[i]*_A.imagp[i];
    maxMag = mag > maxMag ? mag : maxMag;
  }
  for(int i=0; i<nOver2; i++) {
    // Calculate the magnitude
    float mag = _A.realp[i]*_A.realp[i]+_A.imagp[i]*_A.imagp[i];
   // Bind the value to be less than 1.0 to fit in the graph
   amp[i] = [EZAudio MAP:mag leftMin:0.0 leftMax:maxMag rightMin:0.0 rightMax:1.0];
 }

我修改了上面的updateFFTWithBufferSize方法,这样我就可以得到以赫兹表示的频率,如下所示:

代码语言:javascript
运行
复制
for(int i=0; i<nOver2; i++) {
    // Calculate the magnitude
    float mag = _A.realp[i]*_A.realp[i]+_A.imagp[i]*_A.imagp[i];
    if(maxMag < mag) {
        _i_max = i;
    }
    maxMag = mag > maxMag ? mag : maxMag;
}

float frequency = _i_max / bufferSize * 44100;
NSLog(@"FREQUENCY: %f", frequency); 

我已经产生了几个纯正弦音调与奥迪在不同的频率进行测试。我看到的问题是,对于两个相对接近的正弦音调,代码返回的频率是相同的。

例如:在19255 as时产生的正弦音将从FFT中显示为19293.750000Hz。在19330赫兹时产生的正弦音也是如此。在计算中一定有什么不对劲。

任何帮助,我可以修改上述代码,以获得一个更精确的FFT频率读数的纯正弦音调,是非常感谢的。谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-01-27 01:18:41

你可以得到一个粗略的频率估计,通过拟合一条抛物线曲线到3个FFT仓的峰值附近,然后找出该抛物线的极值。

利用FFT窗口的变换作为插值核,并通过逐次逼近改进插值点的最大值估计,可以得到更好的估计值。(零填充和使用长得多的FFT会给出类似的插值估计。)

一个平稳信号的简单方法是,如果可能的话,只需使用更长的FFT和更多的样本,跨越更长的时间间隔。

票数 1
EN

Stack Overflow用户

发布于 2014-01-26 15:28:11

也许你的采样频率不够高?

票数 0
EN

Stack Overflow用户

发布于 2014-01-27 21:56:29

如果你对输入一无所知的话,FFT是一个很好的获得频谱的方法。如果你知道输入是一个纯正弦波,你可以做得更好。从计算FFT开始,得到一个大致的正弦值。得到最小和最大估计幅度或从FFT -平方得到所有输入,加它们,平方根,得到相位在开始和结束给定估计的频率和幅度。

一般来说,你会发现这个阶段不匹配。这是因为末端的相位是2*Δf * N,f-Δf是对频率的一个更好的估计。请记住,这种方法是超噪声敏感的。该方法之所以有效,是因为输入是一个纯正弦波,而噪声是除了那个以外的一切。使用这种方法迭代爆破很快,你甚至碰到四舍五入的错误(也不是正弦波)。

另一个类似的技巧是减去估计的波。两个正弦之间的差异是两个正弦波的乘积,一个加上频率(在你的例子中是±38.5 kHz),另一个减去频率(Δ_f_ < 100 Hz)。另见外差检测

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21365231

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档