【问题标题】:FFT Frequency Bins and PIC32FFT 频率分档和 PIC32
【发布时间】: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));
    }
}

MPLAB Harmony ADC Config

ADC Frequency Bin

Input Signal

非常感谢。

【问题讨论】:

  • 如果你有一个大的 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


【解决方案1】:

Ted 发现microcontroller PIC32MZ Graphics (DA) Family 的数据表12 bit Successive Approximation Register (SAR) Analog-to-Digital Converter (ADC)规范版本 B 之间存在不一致之处

在这两种情况下,驱动 ADC 采样率的时钟源都由寄存器 ADCCON3 的位 ADCSEL&lt;1:0&gt; 控制。

第 452 页的数据表提供了以下时钟源:

11 = FRC
10 = REFCLK3
01 = System Clock (Tcy)
00 = PBCLK3

相反,the specifications of the ADC, in version B, on page 14 是:

11 = System Clock (TCY)
10 = REFCLK3
01 = FRC Oscillator output
00 = Peripheral bus clock (PBCLK)

At the same point, version D of the specifications 声明:

有关 ADC 时钟源的选择,请参阅具体器件数据手册中的“12 位高速逐次逼近寄存器 (SAR)”章节。

MPLAB Harmony ADC 配置器符合此配置。不过采用B版本的时钟设置解决了采样问题,说明家族datasheet不正确。

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

  • CONCLKDIV&lt;5:0&gt; ofADCCON3` : 控制时钟分频器
  • ADCxTIMEADCDIV&lt;6:0&gt; :附加分频器,用于定义单个 ADC 的时钟源。或者 ADCDIV&lt;6:0&gt; ofADCCON2` 用于共享 ADC。
  • ADCxTIME&lt;9:0&gt;ADCCON2&lt;25:16&gt;:时钟滴答数。

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

一旦对采样率进行校正,DFT 就会具有对应于频率或输入信号的最大值。这些频率可以通过应用一个窗口和estimating the frequency of a peak as its mean frequency wih respect to power density来准确识别

【讨论】:

  • 感谢 Francis 详细介绍这一点。
猜你喜欢
  • 1970-01-01
  • 2014-12-18
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
  • 2013-07-13
相关资源
最近更新 更多