【发布时间】:2019-08-03 00:10:40
【问题描述】:
我正在尝试使用可用于 PIC32MZ2064DAB176 的 FFT 库导出音频信号的频率。
我正在使用 MPLAB Harmony 进行配置。
为了测试,使用了两个频率为 1002 Hz 和 750 Hz 的正弦波。这是在在线音调发生器工具的帮助下完成的。我在一个浏览器窗口上有 1002 Hz,在另一个浏览器窗口上有 750 Hz。音频 O/P 插孔的输出经过直流偏置后馈送到微控制器 ADC。
在执行 1.6 V 的直流偏置后,信号被发送到 12 位 ADC。我期望的最大电压是 3 V P-P,所以我猜 1.6 V 的直流偏置就足够了。
信号以 48 kHz 采样,因为我需要读取高达 20 kHz 的频率。
FFT 是一个 1024 点的 FFT。
我能够在频率仓的第 0 个索引中获得 DC 值。
用于从 bin 中获取频率值的公式是 频率 = 索引 * 采样频率 / FFT 点数
但是,对于输入频率的任何值,我总是在第一个和第二个频率箱中获得很高的幅度。据我了解,对于 1002 Hz,幅度应该在频率 bin 的第 21 个索引附近较高,对于 750 Hz 信号,幅度应该在第 16 个索引附近较高。
附上我的代码、ADC Harmony 配置屏幕截图、结果屏幕截图和信号输入屏幕截图。
在代码中,用于频率 bin 的数组是“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));
}
}
非常感谢。
【问题讨论】:
-
如果你有一个大的 DC 值并且你没有应用窗口函数,那么以及 bin 0 中的高幅度你会得到一个从 DC 到一些低频的“裙子”由于频谱泄漏而产生的垃圾箱。如果您绘制幅度谱,您应该会更好地看到发生了什么。
-
哦,我喜欢这类问题。但是,由于具体情况,您可能会在electronics.stackexchange.com 上找到更好的运气。
-
您肯定会查看 所有 箱以查看整个光谱吗?很明显,你找错了。
-
@Clifford,是的,我查看了所有频率区间。它们都是个位数。只有 bin 1 和 2 的值较高
-
已解决。混乱是因为 PIC 数据表。 PIC32MZDA 系列 uC 数据表中,ADCSEL 中的 FRC 设置为 0x11。然而,在 uc 的 ADC 特定数据表 (DS60001344B) 中,FRC 的设置为 0x01。将值设置为 0x11 时,采样频率为 625 kHz。将值设置为 0x01 时,采样率符合要求,即 48 kHz。奇怪的是,MPLAB Harmony 配置器使用的是系列数据表中提到的寄存器值。我现在能够获得频率的索引。非常感谢所有的反馈和建议 :-)
标签: c embedded signal-processing fft