Simple Audio Filter

New to XMOS and XCore? Get started here.
Rammsteiner1988
Member
Posts: 12
Joined: Thu Dec 05, 2013 9:39 am

Simple Audio Filter

Post by Rammsteiner1988 »

Hello everybody,
I modified a example projekt to hear music with out any effect. This is working.

Code: Select all

#include "main.h"

void mymusic(streaming chanend data)
{
    double x;

    while(1)
    {
        data :> x;

        data <: x;
    }
}

int main (void)
{
    streaming chan input_output;

    par
    {
        audio_io( input_output );//I2C connection in another module

        mymusic( input_output );
    }

    return 0;
}
Now I want to write a simple(!) audio filter. So i need to work with coefficients. If I try something like this:

Code: Select all

        data :> x;
        x *= 0.5;
        data <: x;
I cant here anything anymore. I hope you have any ideas.
Sorry for my english, i am from germany ;)
thanks


User avatar
Ross
XCore Expert
Posts: 966
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

My guess is that the data coming in from your audio i/o is not quite in the form you are expecting. Try >> 1 instead of * 0.5..
Rammsteiner1988
Member
Posts: 12
Joined: Thu Dec 05, 2013 9:39 am

Post by Rammsteiner1988 »

Ok shifting is like dividing by 2 isnt it?
But 0.5 was just an example. I need something like

(0,5986+1.1972*x[0]+0,5986*x[1])/(1-2,6346*x[0]+4,029*x[1])

this should be lowpass.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Ok, if you want to do it yourself.

1) You are working with integers here - forget using normalised values - you need to scale up your coefficients so integers makes sense.

2) If you are trying to do an IIR filter your equation is incorrect above. It should be:
a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) + ... + b(nb+1)*x(n-nb)
- a(2)*y(n-1) - ... - a(na+1)*y(n-na)

3) Scale in such as way that a(1) = 2^n, to avoid division and instead use shifting:
Below is an 2:nd order LP-filter scaled by 2^30:

Code: Select all

>> [B,A]=butter(2,0.1); Bint=int32(round(B*2^30)); Aint=int32(round(A*2^30));disp(Bint);disp(Aint)

Bint => 21564350    43128699    21564350
Aint => 1073741824 -1676130396   688645970
4) To calculate the multiplications use the signed multiply-accumulate function (macs) on the integers or use the equivalent C/XC notation.

You can also find existing filterfunctions for XMOS on gitHub https://github.com/xcore/sc_dsp_filters
Rammsteiner1988
Member
Posts: 12
Joined: Thu Dec 05, 2013 9:39 am

Post by Rammsteiner1988 »

thanks a lot for your help.

I found the follwoing transfer function (writen by U. Zölzer)

H(z)=(a0+a1*z^-1+a2*z^-2)/(1+b1*z^-1+b2*z^-2)

can I use this or not??

and could somebody explain the "multiply-accumulate function (macs)" to me?
I just found this:

Code: Select all

// Computes ((long long)a * b) + c.
{result_high, result_low} = macs(a, b, c_high, c_low);
// Computes ((unsigned long long)a * b) + c.
{result_high, result_low} = mac(a, b, c_high, c_low);


but I dont realy understand
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

If you know about transform theory and complex analysis the

H(z)=(a0+a1*z^-1+a2*z^-2)/(1+b1*z^-1+b2*z^-2) will make sense for you, but if the Z-transform (http://en.wikipedia.org/wiki/Z-transform) is like magic, you might look at the equation in the time domain instead.

My Bint and Aint above is the a0, a1, a2 , b0, b1, b2 in the transfer function.

Try to write this with the mac function (x[0] is the in-signal y[0] is the out-signal )

Code: Select all

acc = b0 * x[0] + b1 * x[1] + b2 * x[2] - a1*y[1] - a2*y[2];
y = acc>>30; 

Code: Select all

// l is unsigned int , everything else is int
// put input in x[0]
h=0;l=0;
{h , l } = macs(b0, x[0] ,h , l);
{h , l } = macs(b1, x[1] ,h , l);
{h , l } = macs(b2, x[2] ,h , l);
{h , l } = macs(-a1, y[1] ,h , l);
{h , l } = macs(-a2, y[2] ,h , l);
y[2]=y[1];
y[1]=h<<2;
x[2]=x[1];
x[1]=x[0];
 
//output in h<<2 or y[1]
edit: Changed the code

Above is far from optimal, but a good start to improve further later.
Use my coefs above. They should work with y[1]= h<<2; in the example code

int b0=21564350;
int b1=43128699;
int b2=21564350;
int a1= -1676130396;
int a2= 688645970;
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Ok an simple example

Calculate: A*B+C = 5*6 + 10^12 with XMOS;

The result is larger than 32 bit, we need 64 bits!

10^12 = 0xE8D4A51000;

{result_high, result_low} = macs(a, b, c_high, c_low);

{result_high, result_low} = macs(5, 6, 0xE8, 0xD4A51000);

The result is now stored in result_high, result_low

The answer is: 1000000000030 = E8D4A5101E , that is:
result_high = 0xE8 ;
result_low = 0xD4A5101E;

Try it yourself on XMOS!
Rammsteiner1988
Member
Posts: 12
Joined: Thu Dec 05, 2013 9:39 am

Post by Rammsteiner1988 »

Thank you vry much for your time and work...
but it still not working I only here a terrible noise.

Here is my code:

Code: Select all

#include "main.h"

void mymusic(streaming chanend data)
{
	unsigned int l;
	int x[3],y[3],h;

	int b0=21564350;
	int b1=43128699;
	int b2=21564350;
	int a1= -1676130396;
	int a2= 688645970;

	for (int i =0;i<3;i++)
	{
		x[i]=0;
		y[i]=0;
	}

	while(1)
	{
		
		data :> x[0];
		h=0;
		l=0;
		{h , l } = macs(b0, x[0] ,h , l);
		{h , l } = macs(b1, x[1] ,h , l);
		{h , l } = macs(b2, x[2] ,h , l);
		{h , l } = macs(-a1, y[1] ,h , l);
		{h , l } = macs(-a2, y[2] ,h , l);

		y[2]=y[1];
		y[1]=y[0];
		y[0]= h<<2;
		x[2]=x[1];
		x[1]=x[0];

		data <: y[0];
	}
}

int main (void)
{
	streaming chan input_output;

	par
	{
		audio_io( input_output );//I2C connection in another module

		mymusic( input_output );
	}

	return 0;
}
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Oops, y[0]= h<<2 is too late in the code;
y only needs 2 memory locations, using vectors you could write:
Also, check the MSB by
1) Test to multiply with 3 instead of the filter and then play something not so loud. Does it becomes 3 times louder or just noise ??
or
2) just insert bitrev() and see what happens in audio_io (You have to apply it twice on sender and on reciever);

The normal bit-order of XMOS and the normal bit-order of I2S is different.
Also if your ADC is writing 24 bit's of data you have to check how you build a 32 bit word.
Examine your data from the ADC with some type of probe! Connect a tone-generator to your ADC. Write 1024 samples to a vector (XMOS), and then print out the result. Check that your data makes sense.
Use xSCOPE if possible.

Code: Select all

#include "main.h"

void mymusic(streaming chanend data)
{
	unsigned int l;
	int x[3],y[2],h;

	int b0=21564350;
	int b1=43128699;
	int b2=21564350;
	int a1= -1676130396;
	int a2= 688645970;

	for (int i =0;i<3;i++)
         x[i]=0;
       y[0]=0;
       y[1]=0;

	while(1)
	{
		
		data :> x[0];
		h=0;
		l=0;
		{h , l } = macs(b0, x[0] ,h , l);
		{h , l } = macs(b1, x[1] ,h , l);
		{h , l } = macs(b2, x[2] ,h , l);
		{h , l } = macs(-a1, y[0] ,h , l);
		{h , l } = macs(-a2, y[1] ,h , l);

		y[1]=y[0];
		y[0]=h<<2;
		x[2]=x[1];
		x[1]=x[0];

		data <: y[0];
	}
}

int main (void)
{
	streaming chan input_output;

	par
	{
		audio_io( input_output );//I2C connection in another module

		mymusic( input_output );
	}

	return 0;
}
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Split the problem into the ADC and DAC part.

Write one period of a sine to a 64 sample long vector.
Try and playback the vector in a loop at full volume.

Check that you get a clean sine-wave at fs/64 Hz, and check that you are playing at 0 dBFS (dB Full Scale)

Code: Select all

#include <math.h>
int sine[64];
double A= 2147483647; // 2^31-1
for(int i=0 ; i<64; i++)
 sine[i] = (int) round(A * sin(2PI/(double) i);
replace 2PI with the define within math.h or define it yourself
Post Reply