Logo Search packages:      
Sourcecode: qsstv version File versions  Download package

fft.cpp

/***************************************************************************
                          fft.cpp  -  description
                             -------------------
    begin                : Sat Feb 10 2001
    copyright            : (C) 2001 by Johan Maes - ON1MH
    email                : on1mh@pandora.be
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
/* Based on:
      Program: REALFFT.C
  Author: Philip VanBaren
*/

#include "fft.h"
#include "math.h"
#include "qmessagebox.h"
#include <qpen.h>
#include <qpainter.h>
#include "qsstvglobal.h"
#include "ctext.h"
#include <qwhatsthis.h>



#define FFTAVERAGING 0.6
#define FFTSPAN 2500

fft::fft(QWidget *p,const char *name): QFrame(p,name)
{
      sineTable=NULL;
      bitReversed=NULL;
      arMag=NULL;
      oBuffer=NULL;
      fftTempArray=NULL;
      FFTArray=NULL;
      im=NULL;
      showWaterfall=FALSE;

      QWhatsThis::add( this, specText);


}

fft::~fft()
{
      deleteBuffers();  
}

/** delete allocated buffers */
00058 void fft::deleteBuffers()
{
      if (sineTable) delete sineTable;
      if (bitReversed) delete bitReversed;
      if (arMag) delete arMag;
      if (oBuffer) delete oBuffer;
      if (FFTArray) delete FFTArray;
      if (fftTempArray) delete fftTempArray;
}


/** must be called before performing any FFT */
00070 void fft::initFFT(unsigned int fftLength)
{
      unsigned int i;
      int temp;
      int mask;
      deleteBuffers();
      h=contentsRect().height();
  w=contentsRect().width();
      FFTArray=new QPointArray(w);
      points = fftLength;
      arMag=new uint[fftLength/2];
      fftTempArray=new float[fftLength/2];
      for (i = 0; i <points/2; i++)
            {
                  arMag[i]=0;
                  fftTempArray[i]=0;
            }
      oBuffer=new double[fftLength];

/*
*  FFT size is only half the number of data points
*  The full FFT output can be reconstructed from this FFT's output.
*  (This optimization can be made since the data is real.)
*/
      

      if((sineTable=new double[points])==NULL)
            {
                  QMessageBox::critical( 0,"FFT","Not enough memory for sineTable" );
      return;
            }
      if((bitReversed=new short[points/2])==NULL)
      {
            QMessageBox::critical( 0, "FFT","Not enough memory for bitReversed" );
      return;
      }

      for(i=0;i<points/2;i++)
      {
      temp=0;
      for(mask=points/4;mask>0;mask >>= 1)
         temp=(temp >> 1) + (i&mask ? points/2 : 0);

      bitReversed[i]=temp;
      }

      for(i=0;i<points/2;i++)
            {
      register double s,c;
      s=-sin((2*M_PI*i)/points);
      c=-cos((2*M_PI*i)/points);
      sineTable[bitReversed[i]  ]=s;
      sineTable[bitReversed[i]+1]=c;
      }
      span=(points*FFTSPAN)/isamplingrate;
  im=new QImage(w,h,32);      

}



/** do the actual FFT calculation */

void fft::realFFT(short *iBuffer)
{
      uint i;

      for (i=0;i<points;i++)
            {
                  oBuffer[i]=(double) iBuffer[i];
            }
      int butterfliesPerGroup=points/4;
      endptr1=oBuffer+points;

/*
*  Butterfly:
*     Ain-----Aout
*         \ /
*         / \
*     Bin-----Bout
*/

      while(butterfliesPerGroup>0)
            {
                  A=oBuffer;
      B=oBuffer+butterfliesPerGroup*2;
      sptr=sineTable;

      while(A<endptr1)
            {
            double sin=*sptr;
                              double cos=*(sptr+1);
                              endptr2=B;
                              while(A<endptr2)
                                    {
                  double v1=(*B*cos + *(B+1)*sin);
                  double v2=(*B*sin - *(B+1)*cos);
                              *B=(*A+v1)/2;
                  *(A++)=*(B++)-v1;
                              *B=(*A-v2)/2;
                  *(A++)=*(B++)+v2;
                  }
            A=B;
            B+=butterfliesPerGroup*2;
            sptr+=2;
            }
      butterfliesPerGroup >>= 1;
   }
   /*
    *  Massage output to get the output for a real input sequence.
    */
   br1=bitReversed+1;
   br2=bitReversed+points/2-1;

   while(br1<=br2)
      {
      double temp1,temp2;
      double sin=sineTable[*br1];
      double cos=sineTable[*br1+1];
      A=oBuffer+*br1;
      B=oBuffer+*br2;
      HRplus = (HRminus = *A     - *B    ) + (*B*2);
      HIplus = (HIminus = *(A+1) - *(B+1)) + (*(B+1)*2);
      temp1  = (sin*HRminus - cos*HIplus);
      temp2  = (cos*HRminus + sin*HIplus);
      *B     = (*A     = (HRplus  + temp1)/2) - temp1;
      *(B+1) = (*(A+1) = (HIminus + temp2)/2) - HIminus;

      br1++;
      br2--;
   }
   /*
    *  Handle DC bin separately
    */
  oBuffer[0]+=oBuffer[1];
  oBuffer[1]=0;
  volAvg=0;
      for (i = 0; i <points/2; i++)
      {
                  double re=oBuffer[bitReversed[i]];
                  double im=oBuffer[bitReversed[i]+1];
                  double tmp=sqrt(re*re+im*im);
      arMag[i]=(tmp<0 ? 0 : (int)tmp);
      if(volAvg<arMag[i])
            {
                  volAvg=arMag[i];
//                debug ("vol=%d index=%d",volAvg,i);
            }
    }
    volAvg/=2;
}


00223 void fft::paintEvent(QPaintEvent *p)
{
  draw();
  QFrame::paintEvent(p);
}


00230 void fft::draw()
{
  int i;
  int t;
  QColor c;

      int bw=lineWidth();
  QPainter p(this);

      // shift up image 1 line
  for (i=0;i<(h-1);i++)
      {
            memmove(im->scanLine(i),im->scanLine(i+1),w*sizeof(uint));
      }
  uint *ptr=(uint *)im->scanLine(h-1);

  // pseudo-coloring
      for (i=0; i<w;i++)
            {
                  if (volAvg==0) volAvg=1;
                  int ind=(i*span)/w;
//                double temp=20+50*log( ((double)arMag[ind])/(double)volAvg);
                  //scale between 0 and 1;
                  fftTempArray[i]=fftTempArray[i]*(1-FFTAVERAGING)+FFTAVERAGING*(( (float)arMag[ind])/(float)volAvg); // maximum of 1;
                  uint val=(uint)(fftTempArray[i]*255);
                  if (val>255) val=255;
                  c.setHsv(255-val,255,255);
                  ptr[i]=c.rgb();
//                val=fftArray[i]=3*fftArray[i]/4+val;
//                val=fftArray[i]=fftArray[i]/4+val;
                  t=bw+h-(val*h)/255;
      t=(t<bw ? bw : t);
      FFTArray->setPoint(i,i,t);
            }
      if(showWaterfall)
            {
                  p.drawImage(0,0,*im);
            }
      else
            {
            p.eraseRect(contentsRect());
                  p.setPen(red);
            t=bw+((1200)*w/FFTSPAN);
            p.drawLine(t,bw,t,h+bw);
            p.setPen(blue);
            t=bw+((1500)*w/FFTSPAN);
            p.drawLine(t,bw,t,h+bw);
            t=bw+((2300)*w/FFTSPAN);
            p.drawLine(t,bw,t,h+bw);
            p.setPen(white);
            for (i=0;i<7;i++)
                  {
                  t=bw+(((1600+i*100))*w/FFTSPAN);
                        p.drawLine(t,bw,t,h+bw);
                  }
            p.setPen(green);
                  p.drawPolyline(*FFTArray);
            }
}

void fft::mousePressEvent( QMouseEvent *e )
{
  if (e->button() == LeftButton)
    {
                  showWaterfall=!showWaterfall;
    }
}

Generated by  Doxygen 1.6.0   Back to index