我正在尝试使用可用于PIC32MZ2064DAB176的FFT库来推导音频信号的频率。
我正在使用MPLAB Harmony进行配置。
为了测试,我正在使用两个正弦波,分别是1002 Hz和750 Hz。这是通过在线音调生成器工具完成的。我在一个浏览器窗口中有1002 Hz,在另一个浏览器窗口中有750 Hz。从音频输出插孔输出的信号经过直流偏置后馈送到微控制器ADC。
将信号进行1.6 V的直流偏置后,发送到12位ADC。我期望的最大电压是3 V P-P,因此我认为1.6 V的直流偏置就足够了。
信号以48 kHz的采样率进行采样,因为我需要读取高达20 kHz的频率。
FFT是1024点FFT。
我能够在频率箱的第0个索引中获得直流值。
用于从箱中获取频率值的公式是 Frequency = index * Sampling Frequency / Number of FFT Points
但是,对于任何输入频率的值,我总是在第1个和第2个频率箱中获得高幅度。据我理解,对于1002 Hz,幅度应该在频率箱的第21个索引处较高,并且对于750 Hz信号,幅度应该在约16个索引处较高。
我附上我的代码、ADC Harmony配置截图、结果截图和信号输入截图。
在代码中,用于频率箱的数组是“singleSidedFFT”
非常感谢您能够帮助我推导出正确的频率值。
我正在使用MPLAB Harmony进行配置。
为了测试,我正在使用两个正弦波,分别是1002 Hz和750 Hz。这是通过在线音调生成器工具完成的。我在一个浏览器窗口中有1002 Hz,在另一个浏览器窗口中有750 Hz。从音频输出插孔输出的信号经过直流偏置后馈送到微控制器ADC。
将信号进行1.6 V的直流偏置后,发送到12位ADC。我期望的最大电压是3 V P-P,因此我认为1.6 V的直流偏置就足够了。
信号以48 kHz的采样率进行采样,因为我需要读取高达20 kHz的频率。
FFT是1024点FFT。
我能够在频率箱的第0个索引中获得直流值。
用于从箱中获取频率值的公式是 Frequency = index * Sampling Frequency / Number of FFT Points
但是,对于任何输入频率的值,我总是在第1个和第2个频率箱中获得高幅度。据我理解,对于1002 Hz,幅度应该在频率箱的第21个索引处较高,并且对于750 Hz信号,幅度应该在约16个索引处较高。
我附上我的代码、ADC Harmony配置截图、结果截图和信号输入截图。
在代码中,用于频率箱的数组是“singleSidedFFT”
非常感谢您能够帮助我推导出正确的频率值。
/* FFT */
#define N 1024// Also change the log2N variable below!!
#define SAMPLE_FREQ 48000
#define PI 3.14
// Section: Global Data Definitions
APP_DATA appData;
/* ADC */
long count = 0;
/* FFT */
int16c fftCoefs[N];
int16c *fftc;
int log2N = 10;
extern const int16c twiddleFactors[];
long int freqVector[N];
int16c sampleBuffer[N]; //initialize buffer to collect samples
long int singleSidedFFT[N];
void APP_Tasks ( void )
{
/* Check the application's current state. */
switch ( appData.state )
{
/* Application's initial state. */
case APP_STATE_INIT:
{
bool appInitialized = true;
if (appInitialized)
{
int i;
fftc = &fftCoefs; /* Stores the twiddle factors */
// zero the freqVector and singleSidedFFT
for (i=0; i<N; i++)
{
freqVector = 0;
singleSidedFFT = 0;
sampleBuffer.re = 0;
}
// generate frequency vector this is the x-axis of your single sided fft
for (i=0; i<N; i++)
{
freqVector = i*(SAMPLE_FREQ/2)/((N/2) - 1);
}
/* Calculate the twiddle factors */
DSP_TransformFFT16_setup(fftc, log2N);
appData.state = APP_STATE_SERVICE_TASKS;
}
break;
}
case APP_STATE_SERVICE_TASKS:
{
/* Trigger a conversion */
ADCCON3bits.GSWTRG = 1;
/* Wait the conversions to complete */
while (ADCDSTAT1bits.ARDY2 == 0);
if (count < N)
{
sampleBuffer[count].re = ADCDATA2; /* fetch the result */
sampleBuffer[count].im = 0;
count++;
}
else
{
appData.state = APP_STATE_COMPUTE_FREQ;
count = 0;
}
break;
}
case APP_STATE_COMPUTE_FREQ:
{
APP_ComputeFreq();
appData.state = APP_STATE_SERVICE_TASKS;
break;
}
}
}
void APP_ComputeFreq(void)
{
int i;
int16c dout[N]; //holds computed FFT
int16c scratch[N];
// load complex input data into din
DSP_TransformFFT16(dout, sampleBuffer, fftc, scratch, log2N);
// compute single sided fft
for(i = 0; i < N/2; i++)
{
singleSidedFFT = sqrt((dout.re*dout.re) + (dout.im*dout.im));
}
LATAbits.LATA6 = ~LATAbits.LATA6;
}
我也尝试编写独立的FFT函数,结果是一样的。以下是代码:
void APP_ComputeFreq_2(void)
{
int16_t k, t;
for (k = 0; k < N; k++)
{
// For each output element
int16_t sumreal = 0;
int16_t sumimag = 0;
for (t = 0; t < N; t++)
{
// For each input element
double angle = 2 * M_PI * t * k / N;
sumreal += sampleBuffer[t].re * cos(angle) + sampleBuffer[t].im * sin(angle);
sumimag += -sampleBuffer[t].re * sin(angle) + sampleBuffer[t].im * cos(angle);
}
singleSidedFFT[k] = sqrt((sumreal * sumreal) + (sumimag * sumimag));
}
}
谢谢。