16 位音频的 fftw :: 峰值在 2f 处出现错误

Posted

技术标签:

【中文标题】16 位音频的 fftw :: 峰值在 2f 处出现错误【英文标题】:fftw of 16bit Audio :: peak appearing wrong at 2f 【发布时间】:2015-06-08 15:00:04 【问题描述】:

我正在使用 Port Audio 在我的 PC(-1 和 +1 之间)上获取 32 位浮动音频(44.1Khz),并使用 fftw 获取它。

现在我需要获取 16bit int Audio 并获取它的 fft。我已将音频样本转换为在 -1 和 +1 之间浮动。 fft 可以工作,但峰值出​​现在应有的频率的 2 倍处,因此最大频率分辨率也降低了。因此,对于 44KHz,我可以看到的最大分量约为 10 KHz,而使用 32 位 int/float 时约为 20KHz。

例如,如果我从信号发生器向声卡提供 10KHz 信号,则峰值现在显示为 20KHz。而我唯一改变的是从 paInt32 到 paInt16 的格式。它适用于 paInt32 格式。

  outputStreamParam.channelCount = 1;
  outputStreamParam.device = Pa_GetDefaultOutputDevice();
  outputStreamParam.sampleFormat = paInt16;
  outputStreamParam.suggestedLatency = suggestedLatency;
  outputStreamParam.hostApiSpecificStreamInfo = NULL;

  inputStreamParam.channelCount = 1;
  inputStreamParam.device = Pa_GetDefaultInputDevice();
  inputStreamParam.sampleFormat = paInt16;
  inputStreamParam.suggestedLatency = suggestedLatency;
  inputStreamParam.hostApiSpecificStreamInfo = NULL; 

将 int(16 或 32)转换为 -1 和 +1 之间的浮点数。

int audioProcessor::processingCallback(const void *inputBuffer,
                                        void *outputBuffer,
                                        unsigned long framesPerBuffer,
                                        const PaStreamCallbackTimeInfo* timeInfo,
                                       PaStreamCallbackFlags statusFlags)
   unsigned int i;
     framesPerBuffer = framesPerBuffer/2;

      int *inint = (int*) inputBuffer;

    float *out = (float*) outputBuffer;
    float *in = (float*) inputBuffer;


     for( i=0; i<framesPerBuffer; i++ )
     


        in[i] = inint[i]/2147483647.0f;


     

FFTW 处理器代码。

 this->fftSize = fftSize;
    cout << "Plan start " <<  endl;

  outArraySize = fftSize/2+1;
  cout << "fft Processor start \n";
  fftIn = (double*) fftw_malloc(sizeof(double) * fftSize);
  fftOut = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * outArraySize );
  fftOutAbs = (double*) fftw_malloc(sizeof(double) * outArraySize );

  // fftwPlan = fftw_plan_dft_r2c_1d(fftSize, fftIn, fftOut, FFTW_ESTIMATE);
  cout << "Plan succeed " <<  endl;

    fftwPlan = fftw_plan_dft_r2c_1d(fftSize, fftIn, fftOut, FFTW_MEASURE);

【问题讨论】:

您是否对 16 位和 32 位使用相同的 int->float 转换? 【参考方案1】:

您需要实现两种不同的转换方法。一个用于 int32 浮动,另一个用于 int16 浮动。正如当前实现的那样,它在 int16 情况下使用 int32 转换。这样做的一个问题是转换为浮点数的比例因子是错误的。另一个问题是它跨过输入信号的速度是预期的两倍,这会导致频率全部偏离 2 倍。

对于从 int16 的转换,您需要执行以下操作:

   
   unsigned int i;
   framesPerBuffer = framesPerBuffer/2;

   short *in = (short*) inputBuffer;
   float *out = (float*) outputBuffer;

   for (i=0; i<framesPerBuffer; i++)
   
      out[i] = in[i]/32767.0f;
   

发布代码的另一个问题是它将浮点样本写回错误的缓冲区。自 sizeof(int)==sizeof(float) 以来,您可能没有注意到 int32。

另外,framesPerFrameBuffer = framesPerFrameBuffer/2 是可疑的。我不明白你为什么需要它。

【讨论】:

谢谢,我知道转换的东西有问题。实际上,从 int16 到 float 的转换在我的代码中也很好,可能是编译器在我声明指针时首先将样本转换为 32 位 int。然而,我得到错误频率的原因可能是因为我的指针增加了 4 个字节,所以我总是丢失一个样本,输入信号的处理速度提高了 2 倍。所以现在当我使用你的代码时,我的样本不会丢失并且频率显示正确, 至于 [Code]framesperBuffer [/Code] 这是我不太了解的,当我将 framesperBuffer 用于 int32 时,它运行良好。对于int16,程序开始给出内存错误。对于 int16 framesperBuffer/2 工作正常。同样对于 int 8 framesperBuffer/4 工作正常吗? 通常使用术语帧来指代单个样本乘以通道数,这样如果您有两个数据通道,则一帧将是两个样本。我假设需要除以 2,因为您正在以 2 倍的速度遍历数据。

以上是关于16 位音频的 fftw :: 峰值在 2f 处出现错误的主要内容,如果未能解决你的问题,请参考以下文章

Qt之调用FFTW3实现音频频谱(实现)

更高效的int to double - PortAudio,FFTW - C / C ++

检测音频文件中的小峰值

在 C/C++ 中使用 JACK 和 fftw 的音频频谱

Qt之调用FFTW3实现音频频谱(原理)

一道操作系统题,在一个分页存储管理系统中,逻辑地址长度为16位,页面大小为4096B,现有逻辑地址2F6AH