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
  • Hi Gary,

    The CMSIS FIR function does not have any unusual scaling that you need to follow.  Since you are generating a lowpass filter you can easily determine if the filter is scaled properly by determining its DC response.  Simply sum up the coefficients in the filter and the result should be close to 1.0.  One thing to keep in mind is that you have a relatively short FIR filter.  At 24 points with a sample rate of 2 kHz, your frequency resolution is 83 Hz (2000/24) and you thus won't be able to make changes in the frequency domain at a finer resolution than this.

    Could you share your code and we'll take a quick look?

    -Paul

  • 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 Children
More questions in this forum