Adaptive Filter

From Lyra

Jump to: navigation, search

Contents

Introduction

This example models a basic adaptive FIR filter data flow. The adaptive filter accepts a reference noise input x and generates output y, which is compared with a desired signal d to yield an error signal e. The error signal is then fed back to the adaptive filter to adjust its coefficients w using a least mean squares algorithm. The computation nodes are connected with FIFO channels. The numbers on the channels represent the data flow rates. Three channels are fed with initial tokens for signals x, w and d.

Data Flow

The data flow model of the adaptive filter is shown in the following figure.

Adaptive Filter Data Flow
Adaptive Filter Data Flow

Modeling

We can directly map the adaptive filter’s data flow to a model. Every computation node maps into a process. Every FIFO channel maps into a pair of single state processes (get and put) sharing a circular buffer. The computation nodes interact with the get and put processes to consume and produce tokens respectively.

Noise Input Signal Generator

The following module generates the noisy input signal x by reading from an input file.

module generator(out <int> X)
{
	reg uint N, NS, T, I;
	reg int[22] NX;
	reg _FILE_ xFile;
	init {
		xFile = _fopen_("NOISE", "r");
		N = 21;
		NS = 40;
		T = 0;
		I = 0;
	}

	fsm noise_gen
	{
		val int xn;
		init Sinit:
		{
			when (I <= N)
			{
				NX[I] = 0;
				I = I + 1;
				goto Sinit;
			}
			when (I > N)
			{
				I = 0;
				goto S0;
			}
		}
		state S0:
		{
			when (T < NS)
			{
				xn = _fread_int_(xFile);
                                NX[0] = xn;
				T = T + 1;
				goto S1;	
			}
			when (T == NS)
			{
				_fclose_(xFile);
				_print_("processing done !");
				goto Done;
			}
		}
		state S1:
		{
			when (I <= N, X)
			{
				X.write(NX[I]);
				I = I + 1;
				goto S1;
			}
			when (I > N)
			{
				I = N;
				goto S2;
			}
		}
		state S2:
		{
			when (I > 0)
			{
				NX[I] = NX[I-1];
				I = I - 1;
				goto S2;
			}
			when (I == 0)
			{
				goto S0;
			}
		}
		state Done:
		{
			goto Done;
		}
	}
}

Desire Input Signal Generator

The following module generates the desire input signal d by reading from an input file.

module desire(out <int> D)
{
        reg uint T, NS;
        reg _FILE_ dFile;
        init {
                dFile = _fopen_("DESIRED", "r");
                T = 0;
		NS = 40;
        }

        fsm desired_gen
        {
                val int d;
                init S0:
                {
                        when (T < NS, D)
                        {
                                d = _fread_int_(dFile);
                                D.write(d);
                                T = T + 1;
                                goto S0;
                        }
                        when (T == NS)
                        {
                                _fclose_(dFile);
                                goto done;
                        }
                }
		state done:
		{
			goto done;
		}
        }
}

Channel

The following module models the FIFO channel in the data flow.

#define Num 30
template <int ntoken>
module channel(in <int> in1, out <int> out1)
{
        reg int[Num] data;
        reg int head, tail;
        init{
                head = 0;
                tail = ntoken;
        }
        fsm get
        {
                init S0:
                {
                        when (head != tail, out)
                        {
                                out.write(data[head]);
                                head = (head + 1) % Num;
                                goto S0;
                        }
                }
        }
        fsm put
        {
                init S0:
                {
                        when (((tail + Num - head) % Num) < (Num - 1), in)
                        {
                                data[tail] = in.read();
                                tail = (tail + 1) % Num;
                                goto S0;
                        }
                }
        }
}

Duplicator

The following module models the duplicator node in the data flow. It consumes one token from its input channel, and produces one token to each outgoing channel. The output tokens have the same value as the consumed input one.

module duplicator(in <int> in1, out <int> out1, out <int> out2)
{
	fsm duplicate
	{
		val int data;
		init S0:
		{
			when (in, out1, out2)
			{
				data = in.read();
				out1.write(data);
				out2.write(data);
				goto S0;	
			}
		}
	}
}

Multiplier

The following module models a computation node, the multiplier. It is an asynchronous style modeling of the multiplication.

template <int para>
module multiplier (in <int> X, in <int> Y, out <int> Z)
{
	reg int x, y;
	fsm multiply
	{
		val int z;
		init S0:
		{
			when (X)
			{
				x = X.read();
				goto S1;		
			}
		}
		state S1:
		{
			when (Y) 
			{
				y = Y.read();
				goto S2;
			}
		}
		state S2:
		{
			when (Z)
			{
				z = x * y/para;
				Z.write(z);	
				goto S0;
			}
		}
	}
}

Accumulator

This following models a computation node, the single input accumulator which produces the output signal y.

#define N 21

module accumulator(in <int> A,  out <int> S)
{
	reg uint i; 
	reg int sum;
	init {
		i = 0;
		sum = 0;
	}
	fsm accumulate
	{
		init S0:
		{
			when (i <= N, A)
			{
				sum = sum + A.read();
				i = i + 1;
				goto S0;
			} 
			when (i > N, S)
			{
				S.write(sum);
				_print_(sum);
				sum = 0;
				i = 0;
				goto S0;
			}
		}
	}
}

Differentiator

The following module models the differenciator which compares the difference between the output signal y and the desire signal d to generate the error signal e .

module differentiator(in <int> Y, in <int> D, out <int> E)
{
	reg int y, d;
	reg int i;
	init {
		i = 0;
	}
	
	fsm differentiate
	{
		val int e;
		init S0:
		{
			when (Y)
			{
				y = Y.read();
				goto S1;
			}
		}
		state S1:
		{
			when (D)
			{
				d = D.read();
				goto S2;
			}
		}
		state S2:
		{
			when (i <= N, E)
			{
				e = d - y;
				E.write(e);
				i = i + 1;
				goto S2;	
			}
			when (i > N)
			{
				i = 0;
				goto S0;
			}
		}
	}
}

Adder

The following module models a computation node, the adder with two inputs which adjusts the coefficient w of the adaptive filter. It is an asynchronous style modeling of the addition.

module adder(in <int> A, in <int> B, out <int> S)
{
	reg int a, b;
	fsm add
	{
		val int s;
		init S0:
		{
			when(A)
			{
				a = A.read();
				goto S1;
			}
		}
		state S1:
		{
			when(B)
			{
				b = B.read();
				goto S2;
			}
		}
		state S2:
		{
			when(S)
			{
				s = a + b;
				S.write(s);
				goto S0;
			}
		}
	}
}

toplevel

It instantiates the above modules and makes the connections.

#include "accumulator.rfm"
#include "duplicator.rfm"
#include "differentiator.rfm"
#include "channel.rfm"
#include "desire.rfm"
#include "adder.rfm"
#define BETA 1000000

module toplevel
{
        rendv Xin, X1in, X2in, PWin, Win, W1in, W2in, Yin, PYin, Din, Ein;
        rendv Xout, X1out, X2out, PWout, Wout, W1out, W2out, Yout, PYout, Dout, Eout;
        generator noisy_input(Xin);
        channel #<0> c1(Xin, Xout);
        duplicator dup1(Xout, X1in, X2in);
        channel #<0> c3(X1in, X1out);
        channel #<0> c2(X2in, X2out);
        multiplier #<1> mul1(X2out, W1out, PYin);
        channel #<0> c4(PYin, PYout);
        accumulator acm(PYout, Yin);
        channel #<0> c5(Yin, Yout);
        differentiator diff(Yout, Dout, Ein);
        channel #<0> c6(Din, Dout);
        desire des(Din);
        channel #<0> c7(Ein, Eout);
        multiplier #<BETA>  mul2(Eout, X1out, PWin);
        channel #<0> c8(PWin, PWout);
        adder ad(PWout, W2out, Win);
        channel #<22> c10(Win, Wout);
        duplicator dup2(Wout, W1in, W2in);
        channel #<0> c9(W2in, W2out);
        channel #<0> c11(W1in, W1out);
}
Personal tools