硬汉嵌入式论坛

 找回密码
 立即注册
查看: 7155|回复: 6
收起左侧

[有问必答] FFT最大频率计算

[复制链接]

5

主题

18

回帖

33

积分

新手上路

积分
33
发表于 2021-1-18 13:45:37 | 显示全部楼层 |阅读模式
           大神们,我们产品做呼吸数据的采集,正常的人体呼吸频率在0.2到0.3HZ之间,我们使用单通道ADC_DMA采集,ADC的采样频率为200hz, 5s采集1024个16bit buffer 数据,在DMA的中断发生时,直接将这1024个点数据传给fft算法进行计算,发现最大的频率点在0.17hz左右,计算最大频率的公式为f=Fs*m/N ,其中Fs为采样频率,这里为0.2hz ,m为计算 出的最大index值,N=1024。请大神们指教,这种方法或者说数据采集有问题吗?以下为ADC的配置代码,系统时钟为84MHZ:
void bsp_InitADC(void)
{  
    ADC_InitTypeDef       ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    DMA_InitTypeDef       DMA_InitStructure;
    GPIO_InitTypeDef      GPIO_InitStructure;
                NVIC_InitTypeDef NVIC_InitStructure;

    /* ê1Äü ADC3, DMA2 oí GPIO ê±Öó ****************************************/
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    /* DMA2 Stream0 channel2 ÅäÖÃ **************************************/
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC1ConvertedValue;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = 1024;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
               
               
                DMA_ClearFlag(DMA2_Stream0,DMA_IT_TC);
    DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE); // ÖD¶Ï               
    DMA_Cmd(DMA2_Stream0, ENABLE);  

   // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);


               

    /* ÅäÖÃADC3í¨μà7òy½ÅÎaÄ£ÄaêäèëÄ£ê½******************************/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /****************************************************************************   
          PCLK2 = HCLK / 2
          ÏÂÃæÑ¡ÔñμÄêÇ2·ÖÆμ
          ADCCLK = PCLK2 /2 = HCLK / 4 = 168 / 4 = 42M
      ADC2éÑùÆμÂê£o Sampling Time + Conversion Time = 3 + 12 cycles = 15cyc
                    Conversion Time = 42MHz / 15cyc = 2.8Mbps.
        *****************************************************************************/
    /* ADC1«122¿·Ö3õê¼»ˉ**********************************************************/
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);

    /* ADC3 3õê¼»ˉ ****************************************************************/
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    /* ADC3 1æÔò channel7 ÅäÖÃ *************************************/
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);

    /* ê1ÄüDMAÇëÇó(μ¥ADCÄ£ê½) */
    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

    /* ê1Äü ADC1 DMA */
    ADC_DMACmd(ADC1, ENABLE);

    /* ê1Äü ADC1 */
    ADC_Cmd(ADC1, ENABLE);

    TIM1_Config();
               
                    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117586
QQ
发表于 2021-1-18 15:46:08 | 显示全部楼层
0.2Hz到0.3Hz,那么就是5s左右一个周期,也就是你仅采集了一个周期。

建议多采集几个周期,然后FFT看下效果。
回复

使用道具 举报

5

主题

18

回帖

33

积分

新手上路

积分
33
 楼主| 发表于 2021-1-18 17:13:24 | 显示全部楼层
eric2013 发表于 2021-1-18 15:46
0.2Hz到0.3Hz,那么就是5s左右一个周期,也就是你仅采集了一个周期。

建议多采集几个周期,然后FFT看下 ...

你好,我根据你的建议将采样周期增加到4个左右,也就是20s左右进行一次FFT,这个时候的AD采样率变为了50hz,根据公式f=Fs/N*m,计算出来的频率幅度最大值大于25hz,能帮忙看下什么问题吗?
FFT的计算代码如下:
void FFTTask(void)
{
        uint16_t i;
        float f0;
       
        fftSize = FFT_LENGTH;
       
        float maxValue;
        uint32_t maxIndex;
/*store the adc data as complex data*/
        for(i=0;i<FFT_LENGTH;i++)
        {
                fft_input[2*i] = (float)ADC1ConvertedValue;
                fft_input[2*i+1] = 0;
        }
                /* 1024 complex FFT caculation*/
        arm_cfft_f32(&arm_cfft_sR_f32_len1024, fft_input, ifftFlag,doBitReverse);        //run fft algrithm and store the data into fft_input
        arm_cmplx_mag_f32(fft_input, testOutput, fftSize);//caculate the amplitude of the input data.
        for(int i =0;i<1024;i++)
        {
             printf("%f\r\n",testOutput);
        }
         /* Calculates maxValue and retuns corresponding value */
  arm_max_f32(testOutput, fftSize, &maxValue, &maxIndex);//calculate the max amplitude and corresponding index.
        maxValue = maxValue*2/1024;

        f0 = 50*maxIndex/1024;
  printf("FFT(F32) maxValue %f, maxIndex %d,maxFreq %f\n\r",maxValue,maxIndex,f0);
        /* print the fft data */
        for(i=0; i<fftSize; i++)
        {
                //printf("%f\r\n", testOutput);   //print the amplitude data
        }
        /*run the ifft caculate*/
        ifftFlag = 1;
        arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_input, ifftFlag,doBitReverse);        //run ifft algrithm and store the data into fft_input array.
       
}
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117586
QQ
发表于 2021-1-18 17:23:34 | 显示全部楼层
liwei0225 发表于 2021-1-18 17:13
你好,我根据你的建议将采样周期增加到4个左右,也就是20s左右进行一次FFT,这个时候的AD采样率变为了50h ...

不是,我的意思是你多采集几个周,比如做个4096点FFT
回复

使用道具 举报

5

主题

18

回帖

33

积分

新手上路

积分
33
 楼主| 发表于 2021-1-18 17:35:41 | 显示全部楼层
eric2013 发表于 2021-1-18 17:23
不是,我的意思是你多采集几个周,比如做个4096点FFT

您的意思是在5s内,采集4096个点,然后取其中1024个点做FFT运算吗?那5s内采集的数据可能无法覆盖一个完整的呼吸波形,请问我理解的有问题吗?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117586
QQ
发表于 2021-1-19 07:38:22 | 显示全部楼层
liwei0225 发表于 2021-1-18 17:35
您的意思是在5s内,采集4096个点,然后取其中1024个点做FFT运算吗?那5s内采集的数据可能无法覆盖一个完 ...

不是,是对4096点做FFT,这样你的分辨率更高。
回复

使用道具 举报

0

主题

131

回帖

131

积分

初级会员

积分
131
发表于 2021-1-22 09:28:58 | 显示全部楼层
采样频率为200hz, FFT最高的频率为100Hz
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-16 15:06 , Processed in 0.054345 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表