已解决:FFT频率仓和PIC32

Ted*_*Ted 5 c embedded signal-processing fft

我试图使用可用于PIC32MZ2064DAB176的FFT库导出音频信号的频率。

我正在使用MPLAB Harmony进行配置。

为了进行测试,使用了两个频率为1002 Hz和750 Hz的正弦波。这是借助在线音调生成器工具完成的。我在一个浏览器窗口上有1002 Hz,在另一个浏览器窗口上有750 Hz。直流偏置后,音频O / P插孔的输出被馈送到微控制器ADC。

在执行1.6 V的DC偏置后,信号被发送到12位ADC。我期望的最大电压是3 V PP,因此我猜想DC偏置为1.6 V就足够了。

信号以48 kHz采样,因为我将需要读取高达20 kHz的频率。

FFT是1024点FFT。

我能够在频率档的第0个索引中获得DC值。

用于从仓中获取频率值的公式为:频率=索引*采样频率/ FFT点数

但是,对于任何输入频率值,我总是在第一和第二频率仓中得到很高的幅值。根据我的理解,对于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;
}
Run Code Online (Sandbox Code Playgroud)

我也尝试编写独立的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));
    }
}
Run Code Online (Sandbox Code Playgroud)

MPLAB Harmony ADC配置

ADC频率仓

输入信号

FFT结果2

非常感谢。

fra*_*cis 2

Ted 发现微控制器 PIC32MZ 图形 (DA) 系列的数据表与12 位逐次逼近寄存器 (SAR) 模数转换器 (ADC)规范的版本 B之间存在不一致

\n\n

在这两种情况下,驱动 ADC 采样率的时钟源均由ADCSEL<1:0>寄存器的位控制ADCCON3

\n\n

数据表第 452 页给出了以下时钟源:

\n\n
11 = FRC\n10 = REFCLK3\n01 = System Clock (Tcy)\n00 = PBCLK3\n
Run Code Online (Sandbox Code Playgroud)\n\n

相反,第 14 页 B 版中 ADC 的规格为:

\n\n
11 = System Clock (TCY)\n10 = REFCLK3\n01 = FRC Oscillator output\n00 = Peripheral bus clock (PBCLK)\n
Run Code Online (Sandbox Code Playgroud)\n\n

与此同时,规范的版本 D指出:

\n\n
\n

有关 ADC 时钟源选择,请参阅特定器件数据手册中的 \xe2\x80\x9c12 位高速逐次逼近寄存器 (SAR)\xe2\x80\x9d 章节。

\n
\n\n

MPLAB Harmony ADC 配置器符合此配置。然而,采用版本 B 的时钟设置解决了采样问题,表明该系列数据表不正确。

\n\n

采样率还可能受到以下因素的影响:

\n\n
    \n
  • CONCLKDIV<5:0> ofADCCON3`:控制时钟分频器
  • \n
  • ADCDIV<6:0>of ADCxTIME:附加分频器,用于定义各个 ADC 的时钟源。或者使用ADCDIV<6:0> ofADCCON2` 作为共享 ADC。
  • \n
  • ADCxTIME<9:0>ADCCON2<25:16>:时钟滴答数。
  • \n
\n\n

由于采样远高于预期(625 kHz 对 48 kHz),因此帧的长度(1024 个样本 = 0.0016 秒)与输入信号的周期(约 1 kHz)相当。因此,大部分幅度存储在 DFT 的第一个 bin 中,并且应用窗口并不能解决问题。

\n\n

一旦采样率被校正,DFT 就会具有与频率或输入信号相对应的最大值。通过应用窗口并估计峰值频率作为其相对于功率密度的平均频率,可以准确地识别这些频率

\n