Go Down

Topic: FFT problem (Read 1 time) previous topic - next topic

Dr_Freeman

Mar 17, 2012, 08:46 pm Last Edit: Mar 18, 2012, 10:43 am by Dr_Freeman Reason: 1
I have implemented fft algorithm on my Panda 2 using rlp. The problem is that I sometimes get funky results. For example when I generate sound on my comp I get good frequency reading every forth-fifth time, between that are some random results. Also thing are getting worse when I lower sound frequency, it's getting harder and harder to read right freq value. I suspect that problem lies in microphone calibration. I tried to measure relative silence and set that voltage value as zero. It helped a bit, but not enough. Maybe I should try 256 point fft instead of 128 point, but I fear that would slow things down significantly. I am using this mic:http://www.mikroprinc.com/proizvodi/elektromehanicke-komponente/audio-komponente/mikrofoni/mikrofon-kapisla-kondenzatorski/index.php?keyword=mikrofon  and this amp circuit:http://lowvoltage.wordpress.com/2011/05/15/lm386-mic-amp/

This is my code:


Code: [Select]

#define pi 3.14159265358979323846
 
float vReal[128];
float vImag[128];
float samples=128;
float sampling=10000;
 
float sqrt(float m)
{
  float i=0;
  float x1,x2;
  while( (i*i) <= m )
         i+=0.1;
  x1=i;
  int j;
  for(j=0;j<10;j++)
  {
       x2=m;
     x2/=x1;
     x2+=x1;
     x2/=2;
     x1=x2;
  }
  return x2;
}
 
float cos(float x)
{
   x+=1.5707963267944118;
   float x2 = x*x;
   float x4 = x2*x2;
   float t1 = x * (1.0 - x2 / (2*3));
   float x5 = x * x4;
   float t2 = x5 * (1.0 - x2 / (6*7)) / (1.0* 2*3*4*5);
   float x9 = x5 * x4;
   float t3 = x9 * (1.0 - x2 / (10*11)) / (1.0* 2*3*4*5*6*7*8*9);
   float x13 = x9 * x4;
   float t4 = x13 * (1.0 - x2 / (14*15)) / (1.0* 2*3*4*5*6*7*8*9*10*11*12*13);
   float result = t4;
   result += t3;
   result += t2;
   result += t1;
 
   return result;
}
 
 
 
void Windowing(float *vData,unsigned samples)
{
   unsigned i;
   for (i = 0; i < (samples >> 1); i++)
   {
       float indexMinusOne = i;
       float ratio = (indexMinusOne / (samples-1));
       float weighingFactor = 1.0;
       weighingFactor = 0.54 - (0.46 * cos(2.0 * 3.141592653 * ratio));
       vData[i] *= weighingFactor;
       vData[samples - (i + 1)] *= weighingFactor;
   }
}
 
void swap(float *i, float *j)
{
 float temp;
 
 temp = *i;
 *i = *j;
 *j = temp;
}
void Fft(float *vR, float *vI,unsigned samples)
{
   unsigned j = 0;
   unsigned i;
   for (i = 0; i < (samples-1); i++)
   {
       if (i < j)
       {
            swap(&vR[i], &vR[j]);
            swap(&vI[i], &vI[j]);
       }
       unsigned k = (samples >> 1);
       while (k <= j)
       {
            j -= k;
            k >>= 1;
       }
       j += k;
   }
   float c1 = -1.0;
   float c2 = 0.0;
   unsigned l2 = 1;
   unsigned l;
   for (l = 0; l < 7; l++)// 7=exponent(samples)
   {
       unsigned l1 = l2;
       l2 <<= 1;
       float u1 = 1.0;
       float u2 = 0.0;
       for (j = 0; j < l1; j++)
       {
           unsigned i;
            for (i = j; i < samples; i += l2)
            {
                   unsigned i1 = i + l1;
                   float t1 = u1 * vR[i1] - u2 * vI[i1];
                   float t2 = u1 * vI[i1] + u2 * vR[i1];
                   vR[i1] = vR[i] - t1;
                   vI[i1] = vI[i] - t2;
                   vR[i] += t1;
                   vI[i] += t2;
            }
            float z = (u1 * c1) - (u2 * c2);
            u2 = (u1 * c2) + (u2 * c1);
            u1 = z;
       }
       c2 = sqrt((1.0 - c1) / 2.0);
       c2 = -c2;
       c1 = sqrt((1.0 + c1) / 2.0);
   }
      for (i = 0; i < samples; i++)
       {
            vR[i] /= samples;
            vI[i] /= samples;
       }
}
 
float getFundamental(float *vR, float *vI,unsigned samples)
{
   float freq,max;
   unsigned i,maxIndex;
   maxIndex=1;
   max=0.0;
   for (i = 0; i < samples; i++)
   {
       vR[i] = sqrt((vR[i])*(vR[i]) + (vI[i])*(vI[i]));
   }
 
   for(i=1;i<samples/2;i++)
   {
       if(vR[i]>max)
       {
           max=vR[i];
           maxIndex=i;
       }
   }
   freq = maxIndex * sampling / samples;
   return freq;
}
 
int GHAL_AnalogIn_Read(unsigned char channel)
{
       return ((*((int*)(ADC_DATA_BASE_ADDRESS) + channel)) >>8) & 0x3FF;
}
int ReadAudio(unsigned int *generalArray, void **args, unsigned int argsCount ,unsigned int *argSize)
{
 
       int i=0;
       float x;
       unsigned char channel = *(unsigned char*)args[0];
       while(i<samples)
       {
          vImag[i]=0;
          vReal[i] =(unsigned char)GHAL_AnalogIn_Read(channel)-5;//-5 because of my mic
          i++;
          RLPext->Delay(100);
       }
 
 
       Windowing(vReal,samples);
       Fft(vReal, vImag,samples);
       x=getFundamental(vReal, vImag,samples);
 
 
   return x;
}

el_supremo

That's not exactly an Arduino but does it have hardware floating point? If not, you may find that your FFT routine is too slow to keep up with the audio.

A sampling rate of 10kHz with 128-point FFT means each output bin is 39Hz. Is that sufficient resolution for what you are trying to do?

Pete
Don't send me technical questions via Private Message.

Dr_Freeman

Thank you for replying. One methode call from .net MF to RL procedure takes only about 50 ms, so processing is not the problem. Yes, 39 Hz is high enough resolution and that's not the problem either. I suspect that circuit is the problem. Capacitors can cut off some frequencies, so I need some advice about cap values. Has anyone done anything similar before ?

Magician

We did you get this code? It looks like there is no single line w/o an error. Starting from sampling:
Code: [Select]
while(i<samples)
        {
           vImag[i]=0;
           vReal[i] =(unsigned char)GHAL_AnalogIn_Read(channel)-5;//-5 because of my mic
           i++;
           RLPext->Delay(100);
        }

You declare arrays [128] , how could you store 10000 samples?
Btw,
Quote
A sampling rate of 10kHz with 128-point FFT means each output bin is 39Hz.
, 39 should be corrected to 78 Hz.

Dr_Freeman

The code is derived from http://didier.longueville.free.fr/arduinoos/?p=1022. Why would I want to store 10000 samples? I am performing on the fly fft. Get 128 samples, perform fft, send data to .net and repeat. Time needed for one cycle is about 50ms, so I am not loosing too much time on calculations. And I should repeat that fft works fine for lets say 4000 Hz, but when I lower sound frequency I'm starting to get a lot random results.

el_supremo

Quote
39 should be corrected to 78 Hz.

Thanks for the correction. Dunno how I managed that.

Pete
Don't send me technical questions via Private Message.

Go Up