Dependencies:   Harmonic_analyzer

main.cpp

Committer:
nmaududi
Date:
2019-10-29
Revision:
1:d0115b825d39
Parent:
0:05e2c9ca68e2

File content as of revision 1:d0115b825d39:

/*----------------------------------------------------------------------------
Code to generate a 1004Hz tone and complete a harmonic analysis on the output
Note that the PWM output produces the 1004 Hz tone and is routed back into the
analog input to complete harmonic analysis. In the hardware, the output of the 
PWM is routed to the analog in by a jumber wire. 

Generate a 1004Hz tone with PWM, No DAC present within the board. PWM is the
software DAC implementation in order to generate the sine wave
 -------------------------------------------------------------------------------
 Note parts of the Code was borrowed online from: Wim Huiskamp 
 https://os.mbed.com/users/wim/code/SineFromPWM/file/d274003b52e7/main.cpp/
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 Parts of the FFT analysis code was borrowed from Martin Simpson
 ----------------------------------------
 Note parts of the Code was borrowed online from: Martin Simpson
https://os.mbed.com/users/martinsimpson/code/CMSIS_FFT_mbed_os_DAC/file/05e2c9ca68e2/main.cpp/
 
 *----------------------------------------------------------------------------*/

#include "mbed.h"
/* Include arm_math.h mathematic functions */
#include "arm_math.h"
/* Include mbed-dsp libraries */
#include "arm_common_tables.h"
#include "arm_const_structs.h"
#include "math_helper.h"

/* FFT settings */
#define SAMPLES                 512            /* 256 real party and 256 imaginary parts */
#define FFT_SIZE                SAMPLES / 2     /* FFT size is always the same size as we have samples, so 256 in our case */

//Number of dutycycle steps for output wave
#define SINE_STEPS        32
//Frequency of output sine in Hz
#define SINE_OUT_FREQ     1004

//Constants to compute the sine waveform
//#define PI                 3.141592f
#define SINE_STEPS_RAD    (2.0f * PI / (float)SINE_STEPS)

//Table to generate the sine waveform using dutycycles
float sine_duty[SINE_STEPS];


//Frequency of Pulse Width Modulated signal in Hz
#define PWM_FREQ          200000

//Sampling rate for FFT (50KHz)
#define FFT_SAMP_FREQ          10000

//Ticker to update the PWM dutycycle
Ticker pwm_ticker;

/* Global variables */
float32_t Input[SAMPLES];
float32_t Output[FFT_SIZE];
bool      trig=0;
/* MBED class APIs */
PwmOut led(LED1);
AnalogIn   myADC(PA_4);
//PWM pin
PwmOut PwmPin (PB_3); // set this pin for the analog output tone for the sine wave
//AnalogOut  myDAC(D13);
Serial     pc(USBTX, USBRX);
Ticker     timer;
static int idx=0;
void sample(){
    trig=1;
    }
    
//Ticker calls this fucntion to update the PWM dutycycle
void pwm_duty_updater() {
  
  
  PwmPin.write(sine_duty[idx]);  // Set the dutycycle % to next value in array
  idx++;                         // Increment the idx
  if (idx == SINE_STEPS) idx=0;  // Reset the idx when the end has been reached  

}

int main() {
  
  int i;
  
  // Init the duty cycle array
  for (i=0; i<SINE_STEPS; i++) {
    sine_duty[i] = ( sin(i * SINE_STEPS_RAD) + 1.0f ) / 2.0f;  // convert sine (-1.0 .. +1.0) into dutycycle (0.0 .. 1.0)
  }  
    
  // Set PWM frequency to 200 KHz (period = 5 us)
  PwmPin.period( 1.0f / (float) PWM_FREQ);

  // Init the Ticker to call the dutycyle updater at the required interval
  // The update should be at (SINE_STEPS * SINE_OUT_FREQ) 
  pwm_ticker.attach(&pwm_duty_updater, 1.0f / (float)(SINE_STEPS * SINE_OUT_FREQ));

    //arm_cfft_instance_f32 S;   // ARM CFFT module
    float maxValue;            // Max FFT value is stored here
    float maxIndex;         // Index in Output array where max value is
    bool once=0;
    pc.baud(9600);
    pc.printf("Starting FFT\r\n");
            timer.attach_us(&sample,100); //20us 50KHz sampling rate
            for (int i = 0; i < SAMPLES; i += 2) {
                while (trig==0){}
                trig=0;
                Input[i] = myADC.read(); //Real part NB 
                Input[i + 1] = 0;               //Imaginary Part set to zero
                }
            timer.detach();
        // Init the Complex FFT module, intFlag = 0, doBitReverse = 1
        //NB using predefined arm_cfft_sR_f32_lenXXX, in this case XXX is 256
        arm_cfft_f32(&arm_cfft_sR_f32_len256, Input, 0, 1);

        // Complex Magniture Module put results into Output(Half size of the Input)
        arm_cmplx_mag_f32(Input, Output, FFT_SIZE);
        // DC values present, need to remove that portion
      for (int i = 0; i < 127; ++i)
        Output[i] = Output[i + 1]; // copy next element left
     
        //Calculates maxValue and returns corresponding value
        maxValue = Output[0];
        maxIndex = 0;
        for (int i=0; i<FFT_SIZE/2 ; i++){
            if (Output[i]>maxValue){
                maxValue = Output[i];
                maxIndex = i;
                }
         }
       led.period( 1.0/ (((10000.0/2.0)/128.00)*maxIndex+39.06)*1000);// LED blinking at 1 sec if fundamental frequency is 1004 Hz
       led.write(0.5f);      // 50% duty cycle, relative to period
        float freq_bin;
       if (once==0){
        for (int i=0; i<FFT_SIZE/2 ; i++){
            freq_bin = ((FFT_SAMP_FREQ /2)/128.00)*i+39.06; // DC value shows up in the FFT analysis, removing the DC part, as result, need to add 39.68 Hz
            pc.printf("Frequency bin is %f\r\n",freq_bin); //Each bin 10KHz/2/128 = 39.06Hz resolution
            wait_us(100); 
            pc.printf("Maximum output is %f\r\n",(Output[i]/maxValue)*0.9f);
            wait_us(100); 
            }
           once = 1;
           }
}