DFT

  • This is a bare metal simplest possible DFT procedure which I have used for singal transforms, (it is not na FFT!)
  • Discrete fourier transform

    This class takes does some processing and afterwards returns the processed values
    For this to work the idea was to use three classes
    function generator output function generator output

    IOSignal.h

    Input- Output Signal "object"

    Main Idea is to store the input and output within the same class, some sort of "numeric storage"

            #pragma once
            #include < tiostream >
            #include < vector >
            #include < complex >
            using namespace std; 
    
    
              /*
                Global type signal interface ::: IOSignal.h      *
                      
                input |   signal_in  | 
                ----> |    |_   _|   | ------ >  || PROCESS ||
                      |      | |     |                      |
                      |      | |     |                      |
                      |     _| |_                           |
                      |    |_____|    N T E R F A CE <------|  return 
                      |  signal_out  |                                                   
                                                                                                          
              */
              struct IOSignal{
    
                //  domain for input/ output signal manipulation 
              
                 // sampling frequency 
                 double fs;
              
                 // for time domain 
                  vector signal_in; 
                  vector signal_out;
              
                  // for frequency domain 
                  vector> spectrum_in; 
                  vector> spectrum_out; 
              
                  void inputRe(const vector& sIn) {
              
                      this->signal_in = sIn;
              
                   };
              
                   void outputRe(const vector& sOut)
                   {
                       this ->signal_out = sOut;
                   }
    
                   void type(){
        
                    vector ::iterator pos; 
                    cout << "\n INPUT signal :" ; 
                      for ( pos = signal_in.begin(); pos != signal_in.end(); pos++)
                        {
                            cout << *(pos) << " ";
                            
                        }
                        cout << endl; 
        
                      cout << "\n OUTPUT signal :" ; 
                      for ( pos = signal_out.begin(); pos != signal_out.end(); pos++)
                        {
                            cout << *(pos) << " ";                    
                        }
                        cout << endl; 
             };
        
        };
        
    
    
    
    
          

    processing_m.h

          #pragma once
          #include < sstream >
          #include < cmath   >
          #include < complex >
          #include < vector  >
          #include < iostream >
          #include < fstream >
    
          const double PI = 3.14159265358979323846;
    
          /*                  
                ___         | 
              /\  \        |   IOSignal
              /::\  \       |       |              |
            /:/\:\__\      |      |||   |   |    ||| 
            /:/ /:/  /      |.. |||||||||||||||||||||||||.... -> || PROCESSING ||  --> output to IOsignal
          /:/_/:/  /              ||| | ||  ||||   | ||
          \:\/:/  /                |  |  |   ||       | 
            \::/__/                       |
            \:\  \   
              \:\__\  
              \/__/  PROCESSING MODULE
                      Global functions for auxilliary use    
          */
          
              // DSP General module for processing signal interface IOSignal
    
              // GAIN THE SIGNAL ::: 
              // time domain function
    
              void gain( IOSignal& iosig, double fact)
              {
                  // Input Vector
                  vector inVec = iosig.signal_in;
    
                  // Output Vector
                  vector outVec;
                  vector:: iterator p; // pointer u vektor inVec
                      for ( p  = inVec.begin(); p!= inVec.end(); p++)
                      {
                          double value = *(p);
                          iosig.signal_out.push_back(value*fact);
                      }        
              } 
    
              // turn real double values to complex double values for DFT
              vector> real2cpx( IOSignal& iosig)
              {
                vector> cpx;
                    if(iosig.signal_in.empty())
                    {
                      cout << "this signal is empty \n"; 
                      cpx ={0,0};
                    
                    } 
                    else{
    
                        vector x = iosig.signal_in;
                            int N = x.size(); 
    
                            for (size_t i = 0; i < N; i++)
                            {
                                cpx.push_back( {x[i], 0});
                            } 
                        }
                return cpx; // retunr complex vector
              }
              
                // compute DFT from signal interface and return it to freq_dom cpx vector 
                void DFT( IOSignal& iosig) 
                {
    
                  //DFT ::: inputs
                      // input vector 
                      vector x = iosig.signal_in;
                      //int N = x.size();                         //| GRESKA.. NE IDE DO VELICINE X.SIZE() NEGO DO FS !
    
                      int N = iosig.fs;
    
                      std::complex intSum;                   //| take memory for computation
                      iosig.spectrum_in.reserve(N);                  //| write to freq. domain N
                      vector> X = real2cpx(iosig);   //| turn real signal to complex for DFT
                  
                    // loop through each k of DFT 
                        for (int k = 0; k < N; k++)
                        {
                            intSum = complex(0,0);
                            for (int n = 0; n < N; n++)
                            {
                                double realPart = cos( ((2*PI)/N)*k*n); 
                                double imagPart = sin( ((2*PI)/N)*k*n);
                                std::complex w(realPart, -imagPart);
                                intSum += X[n]*w;
                            }
                          iosig.spectrum_in.push_back(intSum);
                        }
    
                    // transformation length 
                    int L  = floor(iosig.spectrum_in.size()/2);
                    double mag; 
                      for (size_t i = 0; i < L ; i++)
                      {
                        //   |a| = ( a^2 + b^2)^0.5
                        mag = sqrt(pow(iosig.spectrum_in[i].real() ,2) + pow(iosig.spectrum_in[i].imag(),2));
                        iosig.spectrum_out.push_back( 2*mag/(2*L));
                      }
                }
        
    
          /*   ___      _       _   _             
              / _ \_ __(_)_ __ | |_(_)_ __   __ _ 
             / /_)/ '__| | '_ \| __| | '_ \ / _` |
            / ___/| |  | | | | | |_| | | | | (_| |
            \/    |_|  |_|_| |_|\__|_|_| |_|\__, |  FUNCTIONS 
                                            |___/ 
          */
          
          
          // write interface to file 
          void ioWriter( IOSignal& interface, string fileName)
            {            
              ofstream os(fileName);
                      // if interface vectors not equal, give some warning 
                      if(interface.signal_in.size() != interface.signal_out.size())
                      {
                          cout << "Vectors in IOSignal unequal... \n";
                          cout << "signal_in.size() taken for the end raw in the file ... \n";
                      }
          
              // print both signals to interface/ signal_in size ... 
              for (int i = 0; i < interface.signal_in.size(); i++)
              {
                os << i << "\t"< cpx_dft; // complex DFT output 
            double abs_val;          // place holder absolute value 
          
            ofstream os(fileName);   // open file to stream data in 
          
            cout << iosig.spectrum_out.size();
          
            for (size_t i = 0; i < iosig.spectrum_out.size() ; i++)
            {
              cpx_dft = iosig.spectrum_out[i];                                 // take single cpx value 
              abs_val = sqrt(pow(cpx_dft.real(),2)  + pow(cpx_dft.imag(),2));   // calcuate magnitude of complex no.      
              os << i << "\t" << abs_val << endl;       
            }      
              os.close(); // close the file 
              cout <<" magnitude of DFT to *.dat exported " << endl; // say when finished       
          }
    
        

    main.cpp

            #include < iostream >
            #include < vector >
              
            using namespace std; 
              
              
            #include "signal_gen.h"
            #include "IOSignal.h"
            #include "processing_m.h"
              
              
                  //*****************************************************************|
                  //
                  //       || signal input ||      
                  //       ||              ||      vector      processing_m.h
                  //       ||  INTERFACE ---------------------------->|| DSP ||     
                  //       ||              ||                             |
                  //       ||signal output<-------------------------------|
                  //
                  //
                  //*****************************************************************|
    
    
                  int main()
                  {
    
                      // INPUT
                      //  
    
                      signal_gen sineSweep;
                  
    
                      // fs= 8096;
                      // f0 =  1
                      // f1 = 10
                      // Amp = 5
                      // PhaseShift = 0
                      // max time = 1;
                      
                 
    
                      // Interfaces 
                      //
                      
                          
                          // CH1:::                     
    
                          signal_gen myWave;
                          myWave.sine(8096,10,5,0,1);    
                          
                          IOSignal channel_01;                  
                          channel_01.signal_in = myWave.getSignal();
                          ioWriter(channel_01,"DFT_mag.dat");
    
                    
                      
                          // CH2:::
                          IOSignal channel02;
                          vector k = sineSweep.getSignal();
                          channel02.signal_in = k;
                          
                          // CH3:::
                          IOSignal channel03;
                          channel03.inputRe(sineSweep.getSignal());
    
                    
                          // gain channel03 x 2 
                             gain(channel03, 2); 
                             ioWriter(channel03,"ioFile.dat");
    
    
                      // random channel 
                          signal_gen gaussian;                       // inicijaliziraj
                          gaussian.random_normal(0,0.3, 1000);       // generiraj  
                          IOSignal channel04;                        // stvori interface                       
                          channel04.inputRe(gaussian.getSignal());   // kopiraj generator u interface 
                          gain(channel04,5);                         // obradi kanal u interfejsu i stavi u output vector 
                          ioWriter(channel04,"io_random.dat");
    
                        
                      cout << endl <<"... end of main"<
    
    
    
    
        

    GnuPlot

            set title "DFT" 
            set xlabel 'Frequency (Hz) '
            set ylabel 'Mag(n)' 
            set yrange [-8:8]
            set xrange [0:50]
            set grid
            plot 'DFT_mag.dat' using 2:3 with line lt -1 lw 1 title 'output'
          
    DFT outcome

    Conclusions

    Lessons learned...

    Another processing examples

    with: "procssing_m.h" and "IOSignal.h" can gain the signal before computing dft .. here two examples