Best way of doing FIR filtering

If you have a simple question and just want an answer.
Oddworld
Member
Posts: 11
Joined: Tue Mar 03, 2015 10:57 am

Best way of doing FIR filtering

Post by Oddworld »

Hi everyone!

I am currently working on a small DSP project where 4 independent cores are doing FIR filtering.
Each core receives audio samples through a channel and output the result back through another channel.

Because I2S_master module work with a single channel input and output, there is a core that simply fetches data from I2S output and separate them into the 4 DSP core input channels. This core also do the opposite by fetching samples from the 4 DSP cores outputs and serialized them into the I2S input channel.

 It looks like that:

      ____                                       ____
      |      |----------   DSP   ----------|      |
  ---|      |----------   DSP   ----------|      |---
  |   |      |----------   DSP   ----------|      |    |
  |   |___|----------   DSP   ----------|___|    |
  |                                                              |
  |                                                              |
  |               _______________                 |
  |_______|      I2S_master     |_______  |
                 |_______________|
 

As long as I am not doing too complex processing inside DSP, everything goes fine, but I can't hear any sound if I try the following code which implements the equation :

y(n) = c(0)*x(n) + c(1)*x(n-1)...+c(NB_COEFF)*x(n - NB_COEFF);


void dsp(streaming chanend input, streaming chanend output)
{

Code: Select all

    unsigned sample = 0;

Code: Select all

    unsigned buffer_index = 0;

Code: Select all

    short buffer[NB_COEFF];

Code: Select all

    short coeff[NB_COEFF] = {14, 25, 40, 60, 82, 103, 115, 108, 72, 0, -110, -254, -419, -583, -719, -801, -803, -708, -513, -228, 121, 497, 855, 1151, 1346, 1413, 1346, 1151, 855, 497, 121, -228, -513, -708, -803, -801, -719, -583, -419, -254, -110, 0, 72, 108, 115, 103, 82, 60, 40, 25, 14};

Code: Select all

    unsigned sample_tmp;

Code: Select all

    int tmp = 0;

Code: Select all

        while(1)

Code: Select all

    {

Code: Select all

        input :> sample_tmp;

Code: Select all

        sample = (short)(sample_tmp>>16);

Code: Select all

                buffer[buffer_index] = sample;

Code: Select all

                tmp = 0;

Code: Select all

#pragma unsafe arrays

Code: Select all

        for(int i = 0; i < 9; i++)

Code: Select all

            tmp = tmp + ((coeff[NB_COEFF - 1 - i] * buffer[(buffer_index+i+1)%NB_COEFF])/0x4000);

Code: Select all

                sample = (short)tmp;

Code: Select all

        output <: (unsigned)(sample<<16);

Code: Select all

       

Code: Select all

        buffer_index++;

Code: Select all

        buffer_index = buffer_index % NB_COEFF;

Code: Select all

    }

Code: Select all

}
I figured out that it depends of the value of NB_COEFF which represent the number of coefficient of my filter.
With less than 10 coefficients, the system works but above this value no sound on any outputs...

Considering that XCores are running at 400MHz, 50 coefficient filtering should be a piece of cake for 48kHz sampling frequency.

Am I doing something wrong?

Thanks

User avatar
infiniteimprobability
Verified
XCore Legend
Posts: 1164
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

Generally this looks sensible. Having a task to split out data to pass onto 4 DSP units makes sense too. Actually, using distributable tasks, that need not even take a whole core..

If you are loosing sound then perhaps it's a timing issue - The backpressure on the communications could break I2S timing. DACs tend to shut down if they don't like the waveforms they see. Howeverr, you should have quite a lot of time - 1300 instruction ticks at 48KHz assuming all 8 cores used at 500MHz (minus overhead).

Check the I2S output on the scope and see if it is being stretched at the beginning of the L/R clock phase, which would indicate a timing issue.

I would strong reccomend you use xscope to graph your input and output samples to see if zero is reallying being passed to I2S output - loads of examples of using xscope are available ncluding https://www.xmos.com//download/public/a ... 0.a%29.pdf

There are loads of other ways of checking timing. Here's a discussion on some of the options:

http://www.xcore.com/questions/2956/measuring-cpu-usage

 

Engineer at XMOS