A Graphic Equaliser using 2 Analog inputs and an Fast Fourier Transform

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
User_4574
Date:
Thu Mar 18 15:15:33 2010 +0000
Commit message:

Changed in this revision

fft.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fft.cpp	Thu Mar 18 15:15:33 2010 +0000
@@ -0,0 +1,161 @@
+/*
+ * This is not my code and I do not take credit for it.
+ * http://www.mit.edu/~emin/source_code/fft/index.html
+ */
+
+#define SIN_2PI_16 0.38268343236508978
+#define SIN_4PI_16 0.707106781186547460
+#define SIN_6PI_16 0.923879532511286740
+#define C_P_S_2PI_16 1.30656296487637660
+#define C_M_S_2PI_16 0.54119610014619690
+#define C_P_S_6PI_16 1.3065629648763766
+#define C_M_S_6PI_16 -0.54119610014619690
+
+/* INPUT: float input[16], float output[16] */
+/* OUTPUT: none */
+/* EFFECTS:  Places the 16 point fft of input in output in a strange */
+/* order using 10 real multiplies and 79 real adds. */
+/* Re{F[0]}= out0 */
+/* Im{F[0]}= 0 */
+/* Re{F[1]}= out8 */
+/* Im{F[1]}= out12 */
+/* Re{F[2]}= out4 */
+/* Im{F[2]}= -out6 */
+/* Re{F[3]}= out11 */
+/* Im{F[3]}= -out15 */
+/* Re{F[4]}= out2 */
+/* Im{F[4]}= -out3 */
+/* Re{F[5]}= out10 */
+/* Im{F[5]}= out14 */
+/* Re{F[6]}= out5 */
+/* Im{F[6]}= -out7 */
+/* Re{F[7]}= out9 */
+/* Im{F[7]}= -out13 */
+/* Re{F[8]}= out1 */
+/* Im{F[8]}=0 */
+/* F[9] through F[15] can be found by using the formula */
+/* Re{F[n]}=Re{F[(16-n)mod16]} and Im{F[n]}= -Im{F[(16-n)mod16]} */
+
+/* Note using temporary variables to store intermediate computations */
+/* in the butterflies might speed things up.  When the current version */
+/* needs to compute a=a+b, and b=a-b, I do a=a+b followed by b=a-b-b.  */
+/* So practically everything is done in place, but the number of adds */
+/* can be reduced by doinc c=a+b followed by b=a-b. */
+
+/* The algorithm behind this program is to find F[2k] and F[4k+1] */
+/* seperately.  To find F[2k] we take the 8 point Real FFT of x[n]+x[n+8] */
+/* for n from 0 to 7.  To find F[4k+1] we take the 4 point Complex FFT of */
+/* exp(-2*pi*j*n/16)*{x[n] - x[n+8] + j(x[n+12]-x[n+4])} for n from 0 to 3.*/
+
+void fft(float input[16],float output[16] ) {
+  float temp, out0, out1, out2, out3, out4, out5, out6, out7, out8;
+  float out9,out10,out11,out12,out13,out14,out15;
+
+  out0=input[0]+input[8]; /* output[0 through 7] is the data that we */
+  out1=input[1]+input[9]; /* take the 8 point real FFT of. */
+  out2=input[2]+input[10];
+  out3=input[3]+input[11];
+  out4=input[4]+input[12];
+  out5=input[5]+input[13];
+  out6=input[6]+input[14];
+  out7=input[7]+input[15];
+
+
+
+  out8=input[0]-input[8];   /* inputs 8,9,10,11 are */
+  out9=input[1]-input[9];   /* the Real part of the */
+  out10=input[2]-input[10]; /* 4 point Complex FFT inputs.*/
+  out11=input[3]-input[11]; 
+  out12=input[12]-input[4]; /* outputs 12,13,14,15 are */
+  out13=input[13]-input[5]; /* the Imaginary pars of  */
+  out14=input[14]-input[6]; /* the 4 point Complex FFT inputs.*/
+  out15=input[15]-input[7];
+
+  /*First we do the "twiddle factor" multiplies for the 4 point CFFT */
+  /*Note that we use the following handy trick for doing a complex */
+  /*multiply:  (e+jf)=(a+jb)*(c+jd) */
+  /*   e=(a-b)*d + a*(c-d)   and    f=(a-b)*d + b*(c+d)  */
+
+  /* C_M_S_2PI/16=cos(2pi/16)-sin(2pi/16) when replaced by macroexpansion */
+  /* C_P_S_2PI/16=cos(2pi/16)+sin(2pi/16) when replaced by macroexpansion */
+  /* (SIN_2PI_16)=sin(2pi/16) when replaced by macroexpansion */
+  temp=(out13-out9)*(SIN_2PI_16); 
+  out9=out9*(C_P_S_2PI_16)+temp; 
+  out13=out13*(C_M_S_2PI_16)+temp;
+  
+  out14*=(SIN_4PI_16);
+  out10*=(SIN_4PI_16);
+  out14=out14-out10;
+  out10=out14+out10+out10;
+  
+  temp=(out15-out11)*(SIN_6PI_16);
+  out11=out11*(C_P_S_6PI_16)+temp;
+  out15=out15*(C_M_S_6PI_16)+temp;
+
+  /* The following are the first set of two point butterfiles */
+  /* for the 4 point CFFT */
+
+  out8+=out10;
+  out10=out8-out10-out10;
+
+  out12+=out14;
+  out14=out12-out14-out14;
+
+  out9+=out11;
+  out11=out9-out11-out11;
+
+  out13+=out15;
+  out15=out13-out15-out15;
+
+  /*The followin are the final set of two point butterflies */
+  output[1]=out8+out9;
+  output[7]=out8-out9;
+
+  output[9]=out12+out13;
+  output[15]=out13-out12;
+  
+  output[5]=out10+out15;        /* implicit multiplies by */
+  output[13]=out14-out11;        /* a twiddle factor of -j */                            
+  output[3]=out10-out15;  /* implicit multiplies by */
+  output[11]=-out14-out11;  /* a twiddle factor of -j */
+
+  
+  /* What follows is the 8-point FFT of points output[0-7] */
+  /* This 8-point FFT is basically a Decimation in Frequency FFT */
+  /* where we take advantage of the fact that the initial data is real*/
+
+  /* First set of 2-point butterflies */
+    
+  out0=out0+out4;
+  out4=out0-out4-out4;
+  out1=out1+out5;
+  out5=out1-out5-out5;
+  out2+=out6;
+  out6=out2-out6-out6;
+  out3+=out7;
+  out7=out3-out7-out7;
+
+  /* Computations to find X[0], X[4], X[6] */
+  
+  output[0]=out0+out2;
+  output[4]=out0-out2;
+  out1+=out3;
+  output[12]=out3+out3-out1;
+
+  output[0]+=out1;  /* Real Part of X[0] */
+  output[8]=output[0]-out1-out1; /*Real Part of X[4] */
+  /* out2 = Real Part of X[6] */
+  /* out3 = Imag Part of X[6] */
+  
+  /* Computations to find X[5], X[7] */
+
+  out5*=SIN_4PI_16;
+  out7*=SIN_4PI_16;
+  out5=out5-out7;
+  out7=out5+out7+out7;
+
+  output[14]=out6-out7; /* Imag Part of X[5] */
+  output[2]=out5+out4; /* Real Part of X[7] */
+  output[6]=out4-out5; /*Real Part of X[5] */
+  output[10]=-out7-out6; /* Imag Part of X[7] */
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Mar 18 15:15:33 2010 +0000
@@ -0,0 +1,71 @@
+/*
+ * This is my code. It takes 16 samples of the analog in pins and writes the values back to the serial port.
+ * Nathan Lasseter 2010
+ */
+
+#include "mbed.h"
+#include "TextLCD.h"
+
+extern void fft(float inarr[16], float outarr[16]);             //look for fft at link not compile time
+
+//Serial pc(USBTX,USBRX);                                       ///dev/ttyACM0 is locked on university pc's
+Serial pc(p9,p10);                                            //So I use /dev/ttyS0 instead
+BusOut bargraph(p21,p22,p23,p24,p25,p26,p27,p28,p29,p30);       //Dot matrix bargraphs horizontal bus
+BusOut graphs(p11,p12,p13,p14,p15,p16,p17,p18);                 //Dot matrix bargraphs vertical bus
+AnalogIn   left(p19);                                           //Left channel input
+AnalogIn   right(p20);                                          //Right channel input
+
+void outputmatrix(float avg, int which) {                       //This is the simple dot matrix driver.
+        switch (which) {                                        //Select a bargraph
+            case 8: graphs = 0xFF;                              //8: off
+            case 0: graphs = 0xFE;                              //0-7 are right to left. They turn on a bargraph by going low.
+            case 1: graphs = 0xFC;
+            case 2: graphs = 0xF8;
+            case 3: graphs = 0xF0;
+            case 4: graphs = 0xE0;
+            case 5: graphs = 0xC0;
+            case 6: graphs = 0x80;
+            case 7: graphs = 0x00;
+        }
+        if (avg > 0.9) { bargraph=0x3FF; return; }              //Same principle, but set a value on the graph.
+        if (avg > 0.8) { bargraph=0x1FF; return; }
+        if (avg > 0.7) { bargraph=0x0FF; return; }
+        if (avg > 0.6) { bargraph=0x07F; return; }
+        if (avg > 0.5) { bargraph=0x03F; return; }
+        if (avg > 0.4) { bargraph=0x01F; return; }
+        if (avg > 0.3) { bargraph=0x00F; return; }
+        if (avg > 0.2) { bargraph=0x007; return; }
+        if (avg > 0.1) { bargraph=0x003; return; }
+        if (avg > 0.0) { bargraph=0x001; return; }
+        bargraph=0x000;                                         //Default to all off
+}
+
+int main() {                                                    //Main code
+    while(1) {
+        int i;
+/*        float leftin[16], leftout[16];                        //While technically it can support 16 bands over each of 2 channels...
+        float rightin[16], rightout[16];
+        for(i=0;i<16;i++) leftin[i] = left;
+        for(i=0;i<16;i++) rightin[i] = right;
+        fft(leftin, leftout);
+        fft(rightin, rightout); */
+        float in[16], out[16], avg[8];                          //I only use 8 on one channel
+        for(i=0;i<16;i++) in[i] = (left + right) / 2;           //So I average the two
+        fft(in, out);
+        for(i=0;i<8;i++) avg[i] = (out[2*i] + out[(2*i)+1]) / 2;    //And then average pairs of bands
+/*        pc.printf("%f %f %f %f  %f %f %f %f\t%f %f %f %f  %f %f %f %f\n",
+            leftout[0], leftout[1], leftout[2], leftout[3],
+            leftout[4], leftout[5], leftout[6], leftout[7],
+            leftout[8], leftout[9], leftout[10], leftout[11],
+            leftout[12], leftout[13], leftout[14], leftout[15]);
+        pc.printf("%f %f %f %f  %f %f %f %f\t%f %f %f %f  %f %f %f %f\n\n",
+            rightout[0], rightout[1], rightout[2], rightout[3],
+            rightout[4], rightout[5], rightout[6], rightout[7],
+            rightout[8], rightout[9], rightout[10], rightout[11],
+            rightout[12], rightout[13], rightout[14], rightout[15]); */
+        pc.printf("%f %f %f %f\t%f %f %f %f\r\n",             //Then print the values to the uart
+            avg[0], avg[1], avg[2], avg[3],
+            avg[4], avg[5], avg[6], avg[7]);
+        for(i=0;i<8;i++) outputmatrix(avg[i], i);               //And display on the bargrpahs
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Mar 18 15:15:33 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0