Using CMSIS DSP Function: arm_fir_f32 - Correct Use?

Hi All;

I have some questions about correct use of the CMSIS DSP library call arm_fir_32. First, I'll provide some background about what I am doing and what the setup is.

I have a STM32F4 Discovery board, using IAR EWARM for programming. Just for testing purposes, I'm generating a low frequency test signal at 40Hz and feeding it into one of the ADC inputs. The signal is biased to swing from 0 to about 2.5Vpp. The signal has a low to moderate amount of broadband noise - but at this point I am not purposely mixing or introducing any other signals with it. There is a timer interrupt set to sample frequency of 2KHz, with a sampling buffer of 2048 samples.

I have already tested and am using the FFT function arm_cfft_f32, and can accurately determine (track) the frequency of the incoming signal when I change it at the source.  This seems to be working well.

Now, I would like to use the arm_fir_32 filter. To do this, I started out reading the documentation from CMSIS on the function. To implement a FIR low pass, to generate the tap coefficients, I am using this website's only tool to do so.

I generated a 4th order filter, and set the sampling rate the same as my software, with a cutoff of 60Hz. I forced generation to 24 taps to be even. So the BLOCK_SIZE is 32, and the number of blocks is 1024/32 = 32.

Following the example from CMSIS  on this function, I believe I've set up correctly. So the chain looks like this:

ADC --> FIR --> FFT

However, I'm not getting the result I would expect. The values returned from the FFT's output buffer are exponentially large (not this way if I comment out /circumvent the FIR calls). This leads me to believe I am missing a step. Do I need to normalize the values? I thought that because I input the rate into the FIR function setup, this wouldn't be required  - but maybe this is incorrect.

Can someone please provide some insight or assistance as to what I am missing or doing incorrectly to apply the FIR processing?

Thank you,

Gary

Parents
  • Please, accept my apology for my previous post, it was uncalled for. Just a bit impatient, I am.

    Paul, I determined the error and your response helped me to do that. Somehow the FIR coefficients were getting trashed the way I was declaring them and thus resulting in all the trash I was seeing. Now, getting

    values that I would have expected. I've created another set of filter coefficients. o to 45Hz, G = 1, 50Hz to 1KHz, G = 0. 1.5dB ripple, -80dB attenuation, 978 taps.

    Could you please elaborate a bit further on your comment about the resolution - if I were to use that calculation, it would now be 2000/978 = 2.05. Are you saying this is the lowest resolution of frequency I can accurately ascertain after processing it through the FFT?

    Why does the number of taps affect the resolution of the FFT which is another function? If so, how can I attain higher frequency resolution without changing sampling frequency, which is at least 40x higher that the highest frequency I am processing (50Hz) ?

    NB - I should have added that I am trying to obtain very high frequency resolution, sub-hertz if possible.

    Again, my apologies and I thank you for taking the time to answer my questions.

    As requested here is sample code that I am using, in the interrupt handler, which is set to run at SAMPLE_FREQ:

    #define SAMPLE_FREQ                (uint32_t)2000
    #define INPUT_SAMPLES              (uint32_t)1024
    #define ADC_COUNTS                 (uint32_t)4096
    #define VREF                       (float32_t)3.2

    void TIM6_DAC_IRQHandler(void)

    {

      if( TIM_GetITStatus(TIM6, TIM_IT_Update) )

      {

        volatile uint16_t uhADCxConvertedValue;

        uint32_t index;    

        float32_t *inputBufPtr;

        float32_t *outputBufPtr;

        float32_t smplRate = 0;

      

        if( sampleCount == 0 )

        {

          arm_fill_f32(0.0, ADC_Values, INPUT_SAMPLES);

        }

        uhADCxConvertedValue = ADC_get();

     

         /* subtract the DC offset that was added as this is not a bipolar ADC */

        ADC_Values[sampleCount] =  ( ((uhADCxConvertedValue * VREF) / ADC_COUNTS) - 1.6);

             

        if(sampleCount++ == INPUT_SAMPLES)

        {

            inputBufPtr = &ADC_Values[0];

            outputBufPtr = &outputBuffer[0];

            arm_fir_instance_f32 S;

            arm_fir_init_f32(&S, FILTER_TAP_NUM, (float32_t *)&filter_taps[0], &firStateF32[0], BLOCK_SIZE);

                          

            for(uint16_t i = 0; i < NUM_BLOCKS; i++)

            {

                arm_fir_f32(&S, inputBufPtr + (i * BLOCK_SIZE), outputBufPtr + (i * BLOCK_SIZE), BLOCK_SIZE);

            }

            /* Process the data through the CFFT/CIFFT module */

            arm_cfft_f32(&arm_cfft_sR_f32_len512, outputBuffer, ifftFlag, doBitReverse);

          

            /* Calculate the magnitude at each bin */

            arm_cmplx_mag_f32(outputBuffer, cfftBuffer, fftSize);    

          

            /* get the maximum energy at index */

            arm_max_f32( cfftBuffer, BLOCK_SIZE, &maxValue, &index );

          

            printf("Max Value = %.1f, at index = %i\n", maxValue, index);

            //compute frequency

            smplRate = (INPUT_SAMPLES / 1.0);

            printf("frequency = %.1f\n", (float32_t)((index * SAMPLE_FREQ) / smplRate) );

            sampleCount = 0;                      

        }

         

         /* Clear TIM6 Capture compare interrupt pending bit */

        TIM_ClearITPendingBit(TIM6, TIM_IT_Update);

      }

    }

Reply
  • Please, accept my apology for my previous post, it was uncalled for. Just a bit impatient, I am.

    Paul, I determined the error and your response helped me to do that. Somehow the FIR coefficients were getting trashed the way I was declaring them and thus resulting in all the trash I was seeing. Now, getting

    values that I would have expected. I've created another set of filter coefficients. o to 45Hz, G = 1, 50Hz to 1KHz, G = 0. 1.5dB ripple, -80dB attenuation, 978 taps.

    Could you please elaborate a bit further on your comment about the resolution - if I were to use that calculation, it would now be 2000/978 = 2.05. Are you saying this is the lowest resolution of frequency I can accurately ascertain after processing it through the FFT?

    Why does the number of taps affect the resolution of the FFT which is another function? If so, how can I attain higher frequency resolution without changing sampling frequency, which is at least 40x higher that the highest frequency I am processing (50Hz) ?

    NB - I should have added that I am trying to obtain very high frequency resolution, sub-hertz if possible.

    Again, my apologies and I thank you for taking the time to answer my questions.

    As requested here is sample code that I am using, in the interrupt handler, which is set to run at SAMPLE_FREQ:

    #define SAMPLE_FREQ                (uint32_t)2000
    #define INPUT_SAMPLES              (uint32_t)1024
    #define ADC_COUNTS                 (uint32_t)4096
    #define VREF                       (float32_t)3.2

    void TIM6_DAC_IRQHandler(void)

    {

      if( TIM_GetITStatus(TIM6, TIM_IT_Update) )

      {

        volatile uint16_t uhADCxConvertedValue;

        uint32_t index;    

        float32_t *inputBufPtr;

        float32_t *outputBufPtr;

        float32_t smplRate = 0;

      

        if( sampleCount == 0 )

        {

          arm_fill_f32(0.0, ADC_Values, INPUT_SAMPLES);

        }

        uhADCxConvertedValue = ADC_get();

     

         /* subtract the DC offset that was added as this is not a bipolar ADC */

        ADC_Values[sampleCount] =  ( ((uhADCxConvertedValue * VREF) / ADC_COUNTS) - 1.6);

             

        if(sampleCount++ == INPUT_SAMPLES)

        {

            inputBufPtr = &ADC_Values[0];

            outputBufPtr = &outputBuffer[0];

            arm_fir_instance_f32 S;

            arm_fir_init_f32(&S, FILTER_TAP_NUM, (float32_t *)&filter_taps[0], &firStateF32[0], BLOCK_SIZE);

                          

            for(uint16_t i = 0; i < NUM_BLOCKS; i++)

            {

                arm_fir_f32(&S, inputBufPtr + (i * BLOCK_SIZE), outputBufPtr + (i * BLOCK_SIZE), BLOCK_SIZE);

            }

            /* Process the data through the CFFT/CIFFT module */

            arm_cfft_f32(&arm_cfft_sR_f32_len512, outputBuffer, ifftFlag, doBitReverse);

          

            /* Calculate the magnitude at each bin */

            arm_cmplx_mag_f32(outputBuffer, cfftBuffer, fftSize);    

          

            /* get the maximum energy at index */

            arm_max_f32( cfftBuffer, BLOCK_SIZE, &maxValue, &index );

          

            printf("Max Value = %.1f, at index = %i\n", maxValue, index);

            //compute frequency

            smplRate = (INPUT_SAMPLES / 1.0);

            printf("frequency = %.1f\n", (float32_t)((index * SAMPLE_FREQ) / smplRate) );

            sampleCount = 0;                      

        }

         

         /* Clear TIM6 Capture compare interrupt pending bit */

        TIM_ClearITPendingBit(TIM6, TIM_IT_Update);

      }

    }

Children