Main Page | Modules | Class Hierarchy | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

Example code
[Fast Fourier Transform]

    #include <otSerial.h>
    #include <otMalloc.h>
    #include <otPrintf.h>
    #include <otTimer.h>
    #include <otMalloc.h>
    #include <otADS868x.h>
    #include <otFFT.h>
    #include <otMath.h>
    
    /*
        ITALIAN ---
        Per questo semplice esperimento collega un filo di qualche centimetro al connettore Y9. 
        L'alta impedenza del campionatore A/D catturerá facilmente il segnale a 50Hz (o 60Hz) 
        della rete e visualizzerá tutte le sue armoniche. 
        Non vedrai un valore preciso della frequenza di rete, 
        questa cambia continuamente con una massima fluttuazione di +/- 0.5Hz
        
        ENGLISH ---
        For this simple experiment, connect a few inches of wire to connector Y9. 
        The high impedance of the A/D sampler will easily capture the network's 50Hz (or 60Hz) 
        signal and display all its harmonics. 
        You will not see a precise value of the mains frequency, 
        this changes continuously with a maximum fluctuation of +/- 0.5Hz
    */
    #define PEAKS       8                   // Maximum number of peaks to detect
    #define SAMPLES     1024                // Number of sampled data
    #define SAMPLING    1000                // Smapling period as us
    #define FREQUENCY   (1E6 / SAMPLING)    // Sampling frequency
    
    F64     * vReal;                        // Real part for FFT
    F64     * vImag;                        // Imaginary part for FFT
    
    int     emissionPeak[PEAKS];            // Emission peaks found
    int     absorptionPeak[PEAKS];          // Absorption peaks found
    int     nEmission;                      // Number of emission peaks found
    int     nAbsorption;                    // Number of absorption peaks found
    
    otADS868x       adc;                    // The ADC sampler
    otFFT           fft;                    // FFT library
    
    // Peak detector
    int detect_peak(
            const double    * data,             // The data
            int             data_count,         // Row count of data
            int             * emi_peaks,        // Emission peaks will be put here
            int             * num_emi_peaks,    // Number of emission peaks found
            int             max_emi_peaks,      // Maximum number of emission peaks
            int             * absop_peaks,      // Absorption peaks will be put here 
            int             * num_absop_peaks,  // Number of absorption peaks found
            int             max_absop_peaks,    // Maximum number of absorption peaks
            double          delta,              // Delta used for distinguishing peaks
            int             emi_first           // Should we search emission peak first of absorption peak first?
            )
    {
        int     i;
        double  mx;
        double  mn;
        int     mx_pos = 0;
        int     mn_pos = 0;
        int     is_detecting_emi = emi_first;
    
    
        mx = data[0];
        mn = data[0];
    
        *num_emi_peaks = 0;
        *num_absop_peaks = 0;
    
        for(i = 1; i < data_count; ++i)
        {
            if(data[i] > mx)
            {
                mx_pos = i;
                mx = data[i];
            }
            if(data[i] < mn)
            {
                mn_pos = i;
                mn = data[i];
            }
    
            if(is_detecting_emi && data[i] < mx - delta)
            {
                if(*num_emi_peaks >= max_emi_peaks) // not enough spaces
                    return 1;
    
                emi_peaks[*num_emi_peaks] = mx_pos;
                ++ (*num_emi_peaks);
    
                is_detecting_emi = 0;
    
                i = mx_pos - 1;
    
                mn = data[mx_pos];
                mn_pos = mx_pos;
            }
            else 
                if((!is_detecting_emi) && data[i] > mn + delta)
                {
                    if(*num_absop_peaks >= max_absop_peaks)
                        return 2;
    
                    absop_peaks[*num_absop_peaks] = mn_pos;
                    ++ (*num_absop_peaks);
    
                    is_detecting_emi = 1;
                    
                    i = mn_pos - 1;
    
                    mx = data[mn_pos];
                    mx_pos = mn_pos;
                }
        }
        return 0;
    }
    
    void setup()
    {
        UartEnableSignals(UART0);
        UartSetBaud(UART0, 115200);
        setStdout(4096, UART0);     // printf output is now directed on UART0
        
        TimerSetAsCounter(TIMER0);
        TimerEnable(TIMER0, true);
        
        DelayMs(1000);
        
        adc.init();
        // Set ADC range
        adc.setRange(otADS868x::UNI_5V);
        
        vReal = (F64 *) _malloc(sizeof(F64) * SAMPLES);
        vImag = (F64 *) _malloc(sizeof(F64) * SAMPLES);
        
        fft.create(vReal, vImag, SAMPLES, FREQUENCY);
        
        printf("Started ...\n");
    }
    
    void loop()
    {
        U32     i;
        F64     f, v;
        // Sample
        adc.read(vReal, SAMPLES, SAMPLING, TIMER0);
    
        fft.clearImaginary();
        // Weigh data
        fft.windowing(otFFT::FFT_WIN_TYP_HAMMING, otFFT::FFT_FORWARD);
        fft.compute(otFFT::FFT_FORWARD);
        fft.complexToMagnitude();
        i = fft.majorPeak(f, v);
        printf("F = %8.3lf Hz, Vpp = %8.3lf mV, Phase = %5.1lf\n", f, v / 2000.0, RAD_TO_DEG(atan2(vImag[i], vReal[i])));
        
        detect_peak(vReal, SAMPLES, emissionPeak, &nEmission, PEAKS, absorptionPeak, &nAbsorption, PEAKS, 1000000, 1);
        if(nEmission > 2) // Not display f = 0 and fundamentals
        {
            for(int i = 2; i < nEmission; i++)
                printf("\tF(%d) = %8.3lf Hz\n", i, fft.frequency(emissionPeak[i]));
        }
    }
   
    
    /* PROGRAM OUTPUT **************************************************************
    
    F =   50.168 Hz, Vpp = 4979.356 mV, Phase = -43.3
        F(2) =  100.515 Hz
        F(3) =  150.641 Hz
        F(4) =  200.930 Hz
        F(5) =  251.163 Hz
        F(6) =  301.302 Hz
        F(7) =  401.805 Hz
    F =   50.167 Hz, Vpp = 4984.208 mV, Phase = -40.8
        F(2) =  100.508 Hz
        F(3) =  150.640 Hz
        F(4) =  200.910 Hz
        F(5) =  251.170 Hz
        F(6) =  301.277 Hz
        F(7) =  401.783 Hz
    F =   50.169 Hz, Vpp = 4977.858 mV, Phase = -43.7
        F(2) =  100.518 Hz
        F(3) =  150.643 Hz
        F(4) =  200.935 Hz
        F(5) =  251.172 Hz
        F(6) =  301.294 Hz
        F(7) =  401.803 Hz
    F =   50.180 Hz, Vpp = 4909.965 mV, Phase = -25.4
        F(2) =  100.535 Hz
        F(3) =  150.664 Hz
        F(4) =  200.998 Hz
        F(5) =  251.200 Hz
        F(6) =  301.362 Hz
        F(7) =  401.862 Hz
    F =   50.182 Hz, Vpp = 4864.171 mV, Phase =  12.5
        F(2) =  100.530 Hz
        F(3) =  150.662 Hz
        F(4) =  200.997 Hz
        F(5) =  251.199 Hz
        F(6) =  301.357 Hz
        F(7) =  401.856 Hz
    F =   50.166 Hz, Vpp = 4936.603 mV, Phase =  32.4
        F(2) =  100.508 Hz
        F(3) =  150.635 Hz
        F(4) =  200.923 Hz
        F(5) =  251.157 Hz
        F(6) =  301.290 Hz
        F(7) =  401.789 Hz
    F =   50.185 Hz, Vpp = 4888.796 mV, Phase =  41.0
        F(2) =  100.538 Hz
        F(3) =  150.676 Hz
        F(4) =  201.013 Hz
        F(5) =  251.220 Hz
        F(6) =  301.394 Hz
        F(7) =  401.897 Hz
    */
footer
otStudio - Library Reference - (C) 2020-23 Officina Turini, All Rights Reserved
Document built with Doxygen 1.4.0