Electronics Intutions

Electronics Intutions

Friday, February 26, 2016

Floating point algorithm to Fixed point : 3 Point Averager FIR Filter

The following example illustrates the ideas in fixed-point arithmetic. If we want to implement any DSP algorithm from floating point implementation to fixed-point we need to understand the effects of quantization.

Three point averager FIR Filter

$$ y[n] = \sum_{k=0}^2 h[k]x[n-k]$$

Lets implement this filter using Q1.3 format arithmetic. 

$$ h[n] = [\frac{1}{3}, \frac{1}{3}, \frac{1}{3}]$$
$$x[n] = [\frac{1}{5}, \frac{2}{5}, \frac{3}{5}, \frac{4}{5}]$$
$$ (ideal) y[n] = [0.0667, 0.2, 0.4, 0.6, 0.4667, 0.2667] $$

Quantize the values of h[n] to a Q1.3 format with rounding to the nearest available value. 

$$ h[n] = [0.3333, 0.3333, 0.3333]$$
$$ Q(h[n]) = [0.375, 0.375, 0.375]$$
$$ Q(h[n])_2 = [0.011, 0.011, 0.011]$$

Q1.3 format can represent values from -1 to +$\frac{7}{8} $ in steps of $\frac{1}{8}$. So, the nearest available value to $\frac{1}{3}$ is $\frac{3}{8}$.
Bear in mind, that the last representation in binary format the binary point we showed is just for our sake, the actual values are just integers, so it's our responsibility to keep scaling factor all the time. 
$$ Q(h[n])_2 = [0011, 0011, 0011]<scale = 3>$$
$$ Q(h[n]) = [3, 3, 3]<scale = 3>$$
Here we represent scaling factor in angular braces<>. 
 $ z<n> == \frac{z}{2^n} $ 

The input values in Q1.3 format 
$$ x[n] = [0.2, 0.4, 0.6, 0.8] $$
$$ Q(x[n]) = [0.25, 0.375, 0.625, 0.75] $$
$$ Q(x[n])_2 = [0.010, 0.011, 0.101, 0.110] $$
$$ Q(x[n]) = [2, 3, 5, 6] <3>$$

Computing y[0]

$$ y[0]_{(2)} = h[0] x[0] $$
$$ 0.011 \times 0.010 = 00.000110 = 0.001 (rounded) $$
$$ y[0]_{(10)} = 0.125 $$
The intermediate result is in Q2.6 format, and the final value is quantized to Q1.3 format using rounding.

Other outputs are also computed in the same way.
$$(computed ) y[n] = [0.125, 0.25, 0.5, 0.625, 0.5, 0.25] $$
where as
$$ (ideal) y[n] = [0.0667, 0.2, 0.4, 0.6, 0.4667, 0.2667] $$



The FIR filter is implemented in C++ using IT++ library. Let us look at the output of the code before looking into the code.
h[n] = [0.333333 , 0.333333 , 0.333333 , ]
Q(h[n]) = [0.375 , 0.375 , 0.375 , ]
Q(h[n]) = [3<3> , 3<3> , 3<3> , ]

x[n] = [0.2 , 0.4 , 0.6 , 0.8 , ]
Q(x[n]) = [0.25 , 0.375 , 0.625 , 0.75 , ]
Q(x[n]) = [2<3> , 3<3> , 5<3> , 6<3> , ]

calculated - Q1.3 
y[n] = [0.125 , 0.25 , 0.5 , 0.625 , 0.5 , 0.25 , ]
actual 
y[n] = [0.0666667 , 0.2 , 0.4 , 0.6 , 0.466667 , 0.266667 , ]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/***********************************************************************************************
   Author: Srinivas Siripurapu
   Email: srinivas.siripurapu@outlook.com
   Description:
        Demonstration of fixed-point implementation of three-point averager FIR Filter
   Library used: it++ 
***********************************************************************************************/
#include <itpp/itbase.h>
#include <itpp/itfixed.h>
using namespace itpp;
using namespace std;


int main() {

vec h ("0.3333333 0.3333333 0.3333333 ");
vec x ("0.2000 0.4000 0.6000 0.8000 ");
cout << "h[n] = [";
for(int i=0; i < length(h); i++)
cout << h(i)<<" , "; 
cout <<"]\n";

Vec<Fix> hfx;

set_fix(hfx,h,3,RND); // Q1.3 Format RND
cout << "Q(h[n]) = [";
for(int i=0; i < length(h); i++)
cout << hfx(i).unfix()<<" , "; 
cout <<"]\n";
cout << "Q(h[n]) = [";
for(int i=0; i < length(h); i++)
cout << hfx(i)<<" , "; 
cout <<"]\n";

cout << "\nx[n] = [";
for(int i=0; i < length(x); i++)
cout << x(i)<<" , "; 
cout <<"]\n";
Vec<Fix> xfx;
set_fix(xfx,x,3,RND); // Q1.3 Format RND 
cout << "Q(x[n]) = [";
for(int i=0; i < length(x); i++)
cout << xfx(i).unfix()<<" , "; 
cout <<"]\n";
cout << "Q(x[n]) = [";
for(int i=0; i < length(x); i++)
cout << xfx(i)<<" , "; 
cout <<"]\n";


// Calculating 3 tap moving average output y 

vec y(length(h)+length(x)-1);


Vec<Fix> yfx(length(y));

Fix accfx;
double acc = 0.0;


for(int i=0; i < length(yfx); i++) {
      acc = 0; 
 accfx = 0.0;
 for(int k=0; k < 3; k++) {
        if ( i-k >= 0 && i-k < length(x)) {
 acc += h(k)*x(i-k);
 accfx += hfx(k) * xfx(i-k);
 }
       }
 y(i) = acc;
 yfx(i) = accfx;
 yfx(i).rshift(3,RND);
}

cout << "\ncalculated - Q1.3 \ny[n] = [";
for(int i=0; i < length(y); i++)
cout << yfx(i).unfix()<<" , "; 
cout <<"]\n";

cout << "actual \ny[n] = [";
for(int i=0; i < length(y); i++)
cout << y(i)<<" , "; 
cout <<"]\n";
return 0;

}

No comments:

Post a Comment