Skip to main content
Formatted correctly
Source Link
chrisl
  • 16.6k
  • 2
  • 18
  • 27

#define LIN_OUT 1 // Include the resources for the linear output function #define Adafruit_ZeroFFT 256 // Sets the ZeroFFT length to 256 points #define MERR 10 // Number of error values to store in elist[MERR] #define PID_ON 1 // Use PID feedback or not #define TRI_PERIOD 100 // Half-period of triangle wave in loops #define F_BLACKMAN 0.02463994238109641755656975202572 // Osillation freq. for Blackman filter #define ARM_MATH_CM0PLUS
#include <arm_common_tables.h> #include <arm_math.h> #include <Adafruit_ZeroFFT.h> #include <SPI.h>

// Photodiode array variables

byte CLKpin = 4; // Arduino pin delivering the clock pulses to pin 3 (CLK) of the TSL1402R byte SIpin = 5; // Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1402R byte AOpin0 = A1; // Arduino pin connected to pin 4 (analog output 1)of the TSL1402R byte AOpin1 = A2; // Arduino pin connected to pin 8 (analog output 2)of the TSL1402R

// Variables for determining the displacment from the ZeroFFT

int maxindex; // Index of the maximum of the ZeroFFT float maxvalue; // For comparing the values of the ZeroFFT to find the global maximum double kmax; // Spatial wavenumber corresponding to the dominant fringe modulation Fourier component float Am; // Real part of Fourier coefficent corresponding to kmax float Bm; // Imag part of Fourier coefficent corresponding to kmax float theta; // Phase angle of Fourier transform at kmax float preTheta = 0; // Storage for previous value of phase angle int Nwrap = 0; // Number of phase wraps float displacement; // Displacement in nanometers float predisplacement; // Storage for initial value of displacement int w = 0; int prevw = 0; int wdiff = 0;

// PID Variables

unsigned long lastTime; double Output=0; // Output value for PID (voltage to the piezoelectric actuator (in millivolts)) double Setpoint; // Desired value of displacement (in nm) double kp = 0 / 1; // 0 proportional gain for PID double ki = 2/1; // (1000 / (138.5)) integral gain for PID //double ki = 2/ 1; // (1000 / (138.5)) integral gain for PID double kd = 0/ 100; // 0 derivative gain for PID double error; // Error signal; difference between setpoint and displacement (in nm) double preverror; // Stores previous value of error for derivative control float esum; // Integral of error signal over time float D; // Derivative of error signal unsigned long time0 = 0; // Used in calculating the derivative term float MSerror = 0; // Mean squared error float RMSerror = 0; // Root mean squared error float elist[MERR];// Array of last MERR error values int jerr = 0; // index of integral error term float runningRMSerror = 0; // RMS error calc'd from elist

float m = 0; // extra variables for one time calculations float pchange = 0; float lastp = 0; float k = 1; int p = 1; float M = 0; //int switchtime = 1200; // Time (in ms) between Setpoint switches

void setup() { Serial.begin(9600); // Initialize serial interface to computer (i.e. serial monitor or plotter) INIT_PHOTO(); // Initialize the photodiode array READ_PHOTO(); // Read the photodiode array DO_ZeroFFT(); // Calculate the ZeroFFT of the photodiode array data FIND_PEAK_INDEX(); // Determine index of peak in ZeroFFT KMAX(); // Calculate spatial wavevector of the interferogram INIT_PHOTO(); // Maybe could be replaced by START_EXPOSURE() READ_PHOTO(); // Read photodiode again in preparation for next step PHASE_ANGLE(); // Calculate the complex phase angle of the ZeroFFT peak DISPLACEMENT(); // Calculate the displacement from the phase angle predisplacement = displacement; // Save the initial displacement corresponding to center of PZT range Setpoint = 0; // Define the initial setpoint delay(100); // Allow things to settle before beginning loop START_EXPOSURE(); // Turn on the photodiode array and begin integrating }

void loop() { KMAX(); // Calculate kmax from previous cycle's ZeroFFT READ_PHOTO(); // Read photodiode array PHASE_ANGLE(); // Calculate complex phase angle corresponding to kmax peak WRAPPING(); // Determine if a phase wrap occurred DISPLACEMENT(); // Calculate the displacement from the unwrapped phase DO_ZeroFFT(); // Calculate the ZeroFFT of the photodiode array data FIND_PEAK_INDEX(); // Determine index of peak in ZeroFFT //OSC_SET(); // Oscillate the setpoint up and down PID_LOOP(); // Perform feedback to follow the setpoint (if PID_ON is set to 1) //OSC_DAC(); // Send an oscillating voltage to the DAC //TRI_DAC(); // Send a triangular wave voltage to the DAC START_EXPOSURE(); // Turn on the photodiode array and begin integrating for next cycle SERIAL_PRINT(); // Print some outputs to the serial USB port }

// Photodiode functions

void ClockPulse() { // For sending clock pulses during reading of photodiode delayMicroseconds(1); digitalWrite(CLKpin, HIGH); digitalWrite(CLKpin, LOW); }

void INIT_PHOTO() { // Intialization of photodiode // Initialize two Arduino pins as digital output: pinMode(CLKpin, OUTPUT); pinMode(SIpin, OUTPUT); // To set up the ADC, first remove bits set by Arduino library, then choose

for ( int i = 0; i < 14; i++ )
{
  digitalWrite(i, LOW);
#define LIN_OUT 1   // Include the resources for the linear output function
#define Adafruit_ZeroFFT 256  // Sets the ZeroFFT length to 256 points
#define MERR 10     // Number of error values to store in elist[MERR]
#define PID_ON 1    // Use PID feedback or not
#define TRI_PERIOD 100 // Half-period of triangle wave in loops
#define F_BLACKMAN 0.02463994238109641755656975202572 // Osillation freq. for Blackman filter
#define ARM_MATH_CM0PLUS    
#include <arm_common_tables.h>
#include <arm_math.h>
#include <Adafruit_ZeroFFT.h>
#include <SPI.h>

// Photodiode array variables

byte CLKpin = 4;    // Arduino pin delivering the clock pulses to pin 3 (CLK) of the TSL1402R
byte SIpin = 5;     // Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1402R
byte AOpin0 = A1;    // Arduino pin connected to pin 4 (analog output 1)of the TSL1402R
byte AOpin1 = A2;    // Arduino pin connected to pin 8 (analog output 2)of the TSL1402R

// Variables for determining the displacment from the ZeroFFT

int maxindex;       // Index of the maximum of the ZeroFFT
float maxvalue;     // For comparing the values of the ZeroFFT to find the global maximum
double kmax;        // Spatial wavenumber corresponding to the dominant fringe modulation Fourier component
float Am;           // Real part of Fourier coefficent corresponding to kmax
float Bm;           // Imag part of Fourier coefficent corresponding to kmax
float theta;        // Phase angle of Fourier transform at kmax
float preTheta = 0; // Storage for previous value of phase angle
int Nwrap = 0;      // Number of phase wraps
float displacement; // Displacement in nanometers
float predisplacement; // Storage for initial value of displacement
int w = 0;
int prevw = 0;
int wdiff = 0;

// PID Variables

unsigned long lastTime;
double Output=0;  // Output value for PID (voltage to the piezoelectric actuator (in millivolts))
double Setpoint;  // Desired value of displacement (in nm)
double kp = 0 / 1;    // 0 proportional gain for PID
double ki = 2/1;  // (1000 / (138.5)) integral gain for PID
//double ki = 2/ 1;  // (1000 / (138.5)) integral gain for PID
double kd = 0/ 100;    // 0 derivative gain for PID
double error;     // Error signal; difference between setpoint and displacement (in nm)
double preverror; // Stores previous value of error for derivative control
float esum;       // Integral of error signal over time
float D;          // Derivative of error signal
unsigned long time0 = 0; // Used in calculating the derivative term
float MSerror = 0;  // Mean squared error
float RMSerror = 0; // Root mean squared error
float elist[MERR];// Array of last MERR error values
int jerr = 0;        // index of integral error term
float runningRMSerror = 0; // RMS error calc'd from elist

float m = 0;      // extra variables for one time calculations
float pchange = 0;
float lastp = 0;
float k = 1;
int p = 1;
float M = 0;
//int switchtime = 1200; // Time (in ms) between Setpoint switches

void setup() {
  Serial.begin(9600); // Initialize serial interface to computer (i.e. serial monitor or plotter)
  INIT_PHOTO();       // Initialize the photodiode array
  READ_PHOTO();       // Read the photodiode array
  DO_ZeroFFT();           // Calculate the ZeroFFT of the photodiode array data
  FIND_PEAK_INDEX();  // Determine index of peak in ZeroFFT
  KMAX();             // Calculate spatial wavevector of the interferogram
  INIT_PHOTO();       // Maybe could be replaced by START_EXPOSURE()
  READ_PHOTO();       // Read photodiode again in preparation for next step
  PHASE_ANGLE();      // Calculate the complex phase angle of the ZeroFFT peak
  DISPLACEMENT();     // Calculate the displacement from the phase angle
  predisplacement = displacement; // Save the initial displacement corresponding to center of PZT range
  Setpoint = 0;       // Define the initial setpoint
  delay(100);         // Allow things to settle before beginning loop
  START_EXPOSURE();   // Turn on the photodiode array and begin integrating
}

void loop() {
  KMAX();                 // Calculate kmax from previous cycle's ZeroFFT
  READ_PHOTO();           // Read photodiode array
  PHASE_ANGLE();          // Calculate complex phase angle corresponding to kmax peak
  WRAPPING();            // Determine if a phase wrap occurred
  DISPLACEMENT();        // Calculate the displacement from the unwrapped phase
  DO_ZeroFFT();              // Calculate the ZeroFFT of the photodiode array data
  FIND_PEAK_INDEX();       // Determine index of peak in ZeroFFT
  //OSC_SET();             // Oscillate the setpoint up and down
  PID_LOOP();              // Perform feedback to follow the setpoint (if PID_ON is set to 1)
  //OSC_DAC();               // Send an oscillating voltage to the DAC
  //TRI_DAC();              // Send a triangular wave voltage to the DAC
  START_EXPOSURE();          // Turn on the photodiode array and begin integrating for next cycle
  SERIAL_PRINT();               // Print some outputs to the serial USB port
}

// Photodiode functions 

void ClockPulse() { // For sending clock pulses during reading of photodiode
  delayMicroseconds(1);
  digitalWrite(CLKpin, HIGH);
  digitalWrite(CLKpin, LOW);
}

void INIT_PHOTO() { // Intialization of photodiode
  // Initialize two Arduino pins as digital output:
    pinMode(CLKpin, OUTPUT);
    pinMode(SIpin, OUTPUT);
  // To set up the ADC, first remove bits set by Arduino library, then choose
 
    for ( int i = 0; i < 14; i++ )
    {
      digitalWrite(i, LOW);
    }
  // Clock out any existing SI pulse through the ccd register:
    for (int i = 0; i < 260; i++)
    {
      ClockPulse();
    }
  // Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    ClockPulse();
    digitalWrite(SIpin, LOW);
    for (int i = 0; i < 260; i++)
    {
      ClockPulse();
    }
}

void READ_PHOTO() { // Read the photodiode
  
  // Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse
  // into the sensors register:
  digitalWrite(SIpin, HIGH);
  ClockPulse();
  digitalWrite(SIpin, LOW);

  // Next, read all 256 pixels in parallel. Store the result in the array. Each clock pulse
  // causes a new pixel to expose its value on the two outputs:
  for (int i = 0; i < 128; i++)
  {
    delayMicroseconds(20);  // We add a delay to stabilize the AO output from the sensor
    ZeroFFT_input[2 * i] = analogRead(AOpin0);        // Output of first half of photodiode array
    ZeroFFT_input[2 * i + 1] = 0;                     // Store zero in the "imaginary" part of the array
    ZeroFFT_input[2 * i + 256] = analogRead(AOpin1);  // Output of second half of photodiode array
    ZeroFFT_input[2 * i + 257] = 0;                   // Store zero in the "imaginary" part of the array
    ClockPulse();
  }

  // Next, AGAIN stop the ongoing integration of light quanta from each photodiode 
  // by clocking in a SI pulse. This is necessary because during the readout operation,
  // the 18th clock pulse starts the integration of light intensity again.
  // This way we can turn on the integration when we want using the START_EXPOSURE() command.
  digitalWrite(SIpin, HIGH);
  ClockPulse();
  digitalWrite(SIpin, LOW);

  // The photodiode remains OFF after this function completes.
  // Call START_EXPOSURE() to turn on the photodiode array and begin integrating.
}

void START_EXPOSURE() { 
  // The photodiode array starts integrating once 18 clock pulses have passed. 
  // At that time, the photodiodes are once again active. We clock out the SI pulse through
  // the 256 bit register in order to be ready to halt the ongoing measurement at our will
  // (by clocking in a new SI pulse):
  // To be used after all calculations are finished, but 
  // before the next photodiode read operation.
  for (int i = 0; i < 260; i++)
  {
    if (i == 18)
    {
      // Now the photodiodes goes active..
      // An external trigger can be placed here
    }
    ClockPulse();
  }
  // Uncomment the next line to increase the integration time.
  //delay(15);// <-- Add 15 ms integration time
}

//Calculation Functions 

void DO_ZeroFFT() {  // Performs the ZeroFFT
  ZeroFFT_reorder();  // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used
  ZeroFFT_run();      // This is the function that actually does the ZeroFFT
  ZeroFFT_mag_lin();  // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long.
}

void FIND_PEAK_INDEX() { // Finds the index of the major peak in the ZeroFFT
  maxvalue = 0;
  maxindex = 0;
  for (int i = 5; i < 128; i++) // Go through each element of the ZeroFFT (skip the DC peak)
  {
    if (ZeroFFT_lin_out[i] > maxvalue) 
    // If the magnitude is larger than the previously seen maximum...
    {
      maxvalue = ZeroFFT_lin_out[i]; // ...store the new max...
      maxindex = i;              // ...and the index at which it occurs.
    }
  }
}

void KMAX() { 
  // Calculates the spatial wavevector of the interferogram corresponding 
  // to the peak in the ZeroFFT.
  kmax = 2 * PI / 256 * maxindex;
}

void PHASE_ANGLE() { // Calculates the complex phase angle of the ZeroFFT peak
  // NOTE: This function must be called BEFORE the ZeroFFT is calculated.
  Am = 0;
  Bm = 0;
  for (int i = 0; i < 256; i++) // Calculate the real and imag Fourier components
  {
    Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part
    Bm = Bm + float ((ZeroFFT_input[2 * i]) * sin(kmax * i)); //magnitude of imaginary part
  }
  theta = atan2(Bm, Am); // Complext phase angle (in radians)
}

void WRAPPING() { // Determines if a phase wrap/unwrap occured and accounts for it
  if ((preTheta ) > (0.5 * PI) && (theta) < (-0.7 * PI)) {
    // Compare the previous theat to the current theta to see if a wrap occured.
    Nwrap = Nwrap + 1; // If so, add 1 to the number of wraps.
  }
  if ((preTheta) < (-0.7 * PI) && (theta) > (0.5 * PI)) {
    // If an unwrap occured (a phase wrap in the other direction)...
    Nwrap = Nwrap - 1; // ...then subtract 1 from the number of wraps.
  }
  preTheta = theta; // Store the current theta for the next cycle
}

void DISPLACEMENT() { // Calculate the displacement after the phase angle is determined
  m =   2 * PI * Nwrap;
  //M = theta + m;
  displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (1 / sqrt(2))) - predisplacement;
  //displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (0.80)) - predisplacement;
}

// Servo Functions

void PID_LOOP() { // Performs feedback signal for PID control
  error = Setpoint - displacement;

  // Store the current error signal; overwrite if necessary
  if( jerr >= MERR ){
    jerr = 0;
  }
  elist[jerr] = error;
  jerr++;

  // Calculate the running RMS error
  runningRMSerror = 0;
  for(int i=0; i<MERR; i++) {
    runningRMSerror += pow(elist[i],2);
  }
  runningRMSerror = sqrt(runningRMSerror/MERR);
  
  // Calculate the mean-squared and root-mean-square errors over all time
  MSerror = (k - 1) / k * MSerror + pow(error, 2) / k; 
  RMSerror = sqrt(MSerror);
  k = k + 1;

  // Integral of error over all time
  esum = esum + error;
  
  // Derivative of error
  time0 = millis();
  D = (error - preverror) / (time0 - lastTime);
  
  // The feedback signal (in millivolts)
  // The minus signs are to make sure the piezo moves in the right direction
  Output = -(kp * error) -(ki * esum) -(kd * D);

  // Send the feedback to the DAC if PID_ON is 1
  /*if (PID_ON) {
    val = offset + Output;
    val = max(val, 0);    // Constrain the output voltage so that is stays in range 
    val = min(val, 4096);
    DAC_TRANSFER();
  }

  // Save the current time and error for calc'ing the derivative next cycle
  lastTime = time0;
  preverror = error;*/
}

void SERIAL_PRINT(){
  
  Serial.print(displacement);
  Serial.print(" , ");
  Serial.println(millis());
  Serial.print(" ") ; 
}

// Clock out any existing SI pulse through the ccd register: for (int i = 0; i < 260; i++) { ClockPulse(); } // Create a new SI pulse and clock out that same SI pulse through the sensor register: digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW); for (int i = 0; i < 260; i++) { ClockPulse(); } }

void READ_PHOTO() { // Read the photodiode

// Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse // into the sensors register: digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW);

// Next, read all 256 pixels in parallel. Store the result in the array. Each clock pulse // causes a new pixel to expose its value on the two outputs: for (int i = 0; i < 128; i++) { delayMicroseconds(20); // We add a delay to stabilize the AO output from the sensor ZeroFFT_input[2 * i] = analogRead(AOpin0); // Output of first half of photodiode array ZeroFFT_input[2 * i + 1] = 0; // Store zero in the "imaginary" part of the array ZeroFFT_input[2 * i + 256] = analogRead(AOpin1); // Output of second half of photodiode array ZeroFFT_input[2 * i + 257] = 0; // Store zero in the "imaginary" part of the array ClockPulse(); }

// Next, AGAIN stop the ongoing integration of light quanta from each photodiode // by clocking in a SI pulse. This is necessary because during the readout operation, // the 18th clock pulse starts the integration of light intensity again. // This way we can turn on the integration when we want using the START_EXPOSURE() command. digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW);

// The photodiode remains OFF after this function completes. // Call START_EXPOSURE() to turn on the photodiode array and begin integrating. }

void START_EXPOSURE() { // The photodiode array starts integrating once 18 clock pulses have passed. // At that time, the photodiodes are once again active. We clock out the SI pulse through // the 256 bit register in order to be ready to halt the ongoing measurement at our will // (by clocking in a new SI pulse): // To be used after all calculations are finished, but // before the next photodiode read operation. for (int i = 0; i < 260; i++) { if (i == 18) { // Now the photodiodes goes active.. // An external trigger can be placed here } ClockPulse(); } // Uncomment the next line to increase the integration time. //delay(15);// <-- Add 15 ms integration time }

//Calculation Functions

void DO_ZeroFFT() { // Performs the ZeroFFT ZeroFFT_reorder(); // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used ZeroFFT_run(); // This is the function that actually does the ZeroFFT ZeroFFT_mag_lin(); // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long. }

void FIND_PEAK_INDEX() { // Finds the index of the major peak in the ZeroFFT maxvalue = 0; maxindex = 0; for (int i = 5; i < 128; i++) // Go through each element of the ZeroFFT (skip the DC peak) { if (ZeroFFT_lin_out[i] > maxvalue) // If the magnitude is larger than the previously seen maximum... { maxvalue = ZeroFFT_lin_out[i]; // ...store the new max... maxindex = i; // ...and the index at which it occurs. } } }

void KMAX() { // Calculates the spatial wavevector of the interferogram corresponding // to the peak in the ZeroFFT. kmax = 2 * PI / 256 * maxindex; }

void PHASE_ANGLE() { // Calculates the complex phase angle of the ZeroFFT peak // NOTE: This function must be called BEFORE the ZeroFFT is calculated. Am = 0; Bm = 0; for (int i = 0; i < 256; i++) // Calculate the real and imag Fourier components { Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part Bm = Bm + float ((ZeroFFT_input[2 * i]) * sin(kmax * i)); //magnitude of imaginary part } theta = atan2(Bm, Am); // Complext phase angle (in radians) }

void WRAPPING() { // Determines if a phase wrap/unwrap occured and accounts for it if ((preTheta ) > (0.5 * PI) && (theta) < (-0.7 * PI)) { // Compare the previous theat to the current theta to see if a wrap occured. Nwrap = Nwrap + 1; // If so, add 1 to the number of wraps. } if ((preTheta) < (-0.7 * PI) && (theta) > (0.5 * PI)) { // If an unwrap occured (a phase wrap in the other direction)... Nwrap = Nwrap - 1; // ...then subtract 1 from the number of wraps. } preTheta = theta; // Store the current theta for the next cycle }

void DISPLACEMENT() { // Calculate the displacement after the phase angle is determined m = 2 * PI * Nwrap; //M = theta + m; displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (1 / sqrt(2))) - predisplacement; //displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (0.80)) - predisplacement; }

// Servo Functions

void PID_LOOP() { // Performs feedback signal for PID control error = Setpoint - displacement;

// Store the current error signal; overwrite if necessary if( jerr >= MERR ){ jerr = 0; } elist[jerr] = error; jerr++;

// Calculate the running RMS error runningRMSerror = 0; for(int i=0; i<MERR; i++) { runningRMSerror += pow(elist[i],2); } runningRMSerror = sqrt(runningRMSerror/MERR);

// Calculate the mean-squared and root-mean-square errors over all time MSerror = (k - 1) / k * MSerror + pow(error, 2) / k; RMSerror = sqrt(MSerror); k = k + 1;

// Integral of error over all time esum = esum + error;

// Derivative of error time0 = millis(); D = (error - preverror) / (time0 - lastTime);

// The feedback signal (in millivolts) // The minus signs are to make sure the piezo moves in the right direction Output = -(kp * error) -(ki * esum) -(kd * D);

// Send the feedback to the DAC if PID_ON is 1 /*if (PID_ON) { val = offset + Output; val = max(val, 0); // Constrain the output voltage so that is stays in range val = min(val, 4096); DAC_TRANSFER(); }

// Save the current time and error for calc'ing the derivative next cycle lastTime = time0; preverror = error;*/ }

void SERIAL_PRINT(){

Serial.print(displacement); Serial.print(" , "); Serial.println(millis()); Serial.print(" ") ; }

/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void READ_PHOTO()': DIS_SET_V04_Arduino-zero:144: error: 'ZeroFFT_input' was not declared in this scope ZeroFFT_input[2 * i] = analogRead(AOpin0); // Output of first half of photodiode array ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void DO_ZeroFFT()': DIS_SET_V04_Arduino-zero:186: error: 'ZeroFFT_reorder' was not declared in this scope ZeroFFT_reorder(); // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used ^ DIS_SET_V04_Arduino-zero:187: error: 'ZeroFFT_run' was not declared in this scope ZeroFFT_run(); // This is the function that actually does the ZeroFFT ^ DIS_SET_V04_Arduino-zero:188: error: 'ZeroFFT_mag_lin' was not declared in this scope ZeroFFT_mag_lin(); // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long. ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void FIND_PEAK_INDEX()': DIS_SET_V04_Arduino-zero:196: error: 'ZeroFFT_lin_out' was not declared in this scope if (ZeroFFT_lin_out[i] > maxvalue) ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void PHASE_ANGLE()': DIS_SET_V04_Arduino-zero:217: error: 'ZeroFFT_input' was not declared in this scope Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part ^ exit status 1 'ZeroFFT_input' was not declared in this scope /Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/mic_tft/mic_tft.ino /Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/normalized/normalized.ino

/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void READ_PHOTO()':
DIS_SET_V04_Arduino-zero:144: error: 'ZeroFFT_input' was not declared in this scope
     ZeroFFT_input[2 * i] = analogRead(AOpin0);        // Output of first half of photodiode array
     ^
/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void DO_ZeroFFT()':
DIS_SET_V04_Arduino-zero:186: error: 'ZeroFFT_reorder' was not declared in this scope
   ZeroFFT_reorder();  // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used
                   ^
DIS_SET_V04_Arduino-zero:187: error: 'ZeroFFT_run' was not declared in this scope
   ZeroFFT_run();      // This is the function that actually does the ZeroFFT
               ^
DIS_SET_V04_Arduino-zero:188: error: 'ZeroFFT_mag_lin' was not declared in this scope
   ZeroFFT_mag_lin();  // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long.
                   ^
/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void FIND_PEAK_INDEX()':
DIS_SET_V04_Arduino-zero:196: error: 'ZeroFFT_lin_out' was not declared in this scope
     if (ZeroFFT_lin_out[i] > maxvalue) 
         ^
/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void PHASE_ANGLE()':
DIS_SET_V04_Arduino-zero:217: error: 'ZeroFFT_input' was not declared in this scope
     Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part
                       ^
exit status 1
'ZeroFFT_input' was not declared in this scope
/Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/mic_tft/mic_tft.ino
/Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/normalized/normalized.ino

#define LIN_OUT 1 // Include the resources for the linear output function #define Adafruit_ZeroFFT 256 // Sets the ZeroFFT length to 256 points #define MERR 10 // Number of error values to store in elist[MERR] #define PID_ON 1 // Use PID feedback or not #define TRI_PERIOD 100 // Half-period of triangle wave in loops #define F_BLACKMAN 0.02463994238109641755656975202572 // Osillation freq. for Blackman filter #define ARM_MATH_CM0PLUS
#include <arm_common_tables.h> #include <arm_math.h> #include <Adafruit_ZeroFFT.h> #include <SPI.h>

// Photodiode array variables

byte CLKpin = 4; // Arduino pin delivering the clock pulses to pin 3 (CLK) of the TSL1402R byte SIpin = 5; // Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1402R byte AOpin0 = A1; // Arduino pin connected to pin 4 (analog output 1)of the TSL1402R byte AOpin1 = A2; // Arduino pin connected to pin 8 (analog output 2)of the TSL1402R

// Variables for determining the displacment from the ZeroFFT

int maxindex; // Index of the maximum of the ZeroFFT float maxvalue; // For comparing the values of the ZeroFFT to find the global maximum double kmax; // Spatial wavenumber corresponding to the dominant fringe modulation Fourier component float Am; // Real part of Fourier coefficent corresponding to kmax float Bm; // Imag part of Fourier coefficent corresponding to kmax float theta; // Phase angle of Fourier transform at kmax float preTheta = 0; // Storage for previous value of phase angle int Nwrap = 0; // Number of phase wraps float displacement; // Displacement in nanometers float predisplacement; // Storage for initial value of displacement int w = 0; int prevw = 0; int wdiff = 0;

// PID Variables

unsigned long lastTime; double Output=0; // Output value for PID (voltage to the piezoelectric actuator (in millivolts)) double Setpoint; // Desired value of displacement (in nm) double kp = 0 / 1; // 0 proportional gain for PID double ki = 2/1; // (1000 / (138.5)) integral gain for PID //double ki = 2/ 1; // (1000 / (138.5)) integral gain for PID double kd = 0/ 100; // 0 derivative gain for PID double error; // Error signal; difference between setpoint and displacement (in nm) double preverror; // Stores previous value of error for derivative control float esum; // Integral of error signal over time float D; // Derivative of error signal unsigned long time0 = 0; // Used in calculating the derivative term float MSerror = 0; // Mean squared error float RMSerror = 0; // Root mean squared error float elist[MERR];// Array of last MERR error values int jerr = 0; // index of integral error term float runningRMSerror = 0; // RMS error calc'd from elist

float m = 0; // extra variables for one time calculations float pchange = 0; float lastp = 0; float k = 1; int p = 1; float M = 0; //int switchtime = 1200; // Time (in ms) between Setpoint switches

void setup() { Serial.begin(9600); // Initialize serial interface to computer (i.e. serial monitor or plotter) INIT_PHOTO(); // Initialize the photodiode array READ_PHOTO(); // Read the photodiode array DO_ZeroFFT(); // Calculate the ZeroFFT of the photodiode array data FIND_PEAK_INDEX(); // Determine index of peak in ZeroFFT KMAX(); // Calculate spatial wavevector of the interferogram INIT_PHOTO(); // Maybe could be replaced by START_EXPOSURE() READ_PHOTO(); // Read photodiode again in preparation for next step PHASE_ANGLE(); // Calculate the complex phase angle of the ZeroFFT peak DISPLACEMENT(); // Calculate the displacement from the phase angle predisplacement = displacement; // Save the initial displacement corresponding to center of PZT range Setpoint = 0; // Define the initial setpoint delay(100); // Allow things to settle before beginning loop START_EXPOSURE(); // Turn on the photodiode array and begin integrating }

void loop() { KMAX(); // Calculate kmax from previous cycle's ZeroFFT READ_PHOTO(); // Read photodiode array PHASE_ANGLE(); // Calculate complex phase angle corresponding to kmax peak WRAPPING(); // Determine if a phase wrap occurred DISPLACEMENT(); // Calculate the displacement from the unwrapped phase DO_ZeroFFT(); // Calculate the ZeroFFT of the photodiode array data FIND_PEAK_INDEX(); // Determine index of peak in ZeroFFT //OSC_SET(); // Oscillate the setpoint up and down PID_LOOP(); // Perform feedback to follow the setpoint (if PID_ON is set to 1) //OSC_DAC(); // Send an oscillating voltage to the DAC //TRI_DAC(); // Send a triangular wave voltage to the DAC START_EXPOSURE(); // Turn on the photodiode array and begin integrating for next cycle SERIAL_PRINT(); // Print some outputs to the serial USB port }

// Photodiode functions

void ClockPulse() { // For sending clock pulses during reading of photodiode delayMicroseconds(1); digitalWrite(CLKpin, HIGH); digitalWrite(CLKpin, LOW); }

void INIT_PHOTO() { // Intialization of photodiode // Initialize two Arduino pins as digital output: pinMode(CLKpin, OUTPUT); pinMode(SIpin, OUTPUT); // To set up the ADC, first remove bits set by Arduino library, then choose

for ( int i = 0; i < 14; i++ )
{
  digitalWrite(i, LOW);
}

// Clock out any existing SI pulse through the ccd register: for (int i = 0; i < 260; i++) { ClockPulse(); } // Create a new SI pulse and clock out that same SI pulse through the sensor register: digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW); for (int i = 0; i < 260; i++) { ClockPulse(); } }

void READ_PHOTO() { // Read the photodiode

// Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse // into the sensors register: digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW);

// Next, read all 256 pixels in parallel. Store the result in the array. Each clock pulse // causes a new pixel to expose its value on the two outputs: for (int i = 0; i < 128; i++) { delayMicroseconds(20); // We add a delay to stabilize the AO output from the sensor ZeroFFT_input[2 * i] = analogRead(AOpin0); // Output of first half of photodiode array ZeroFFT_input[2 * i + 1] = 0; // Store zero in the "imaginary" part of the array ZeroFFT_input[2 * i + 256] = analogRead(AOpin1); // Output of second half of photodiode array ZeroFFT_input[2 * i + 257] = 0; // Store zero in the "imaginary" part of the array ClockPulse(); }

// Next, AGAIN stop the ongoing integration of light quanta from each photodiode // by clocking in a SI pulse. This is necessary because during the readout operation, // the 18th clock pulse starts the integration of light intensity again. // This way we can turn on the integration when we want using the START_EXPOSURE() command. digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW);

// The photodiode remains OFF after this function completes. // Call START_EXPOSURE() to turn on the photodiode array and begin integrating. }

void START_EXPOSURE() { // The photodiode array starts integrating once 18 clock pulses have passed. // At that time, the photodiodes are once again active. We clock out the SI pulse through // the 256 bit register in order to be ready to halt the ongoing measurement at our will // (by clocking in a new SI pulse): // To be used after all calculations are finished, but // before the next photodiode read operation. for (int i = 0; i < 260; i++) { if (i == 18) { // Now the photodiodes goes active.. // An external trigger can be placed here } ClockPulse(); } // Uncomment the next line to increase the integration time. //delay(15);// <-- Add 15 ms integration time }

//Calculation Functions

void DO_ZeroFFT() { // Performs the ZeroFFT ZeroFFT_reorder(); // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used ZeroFFT_run(); // This is the function that actually does the ZeroFFT ZeroFFT_mag_lin(); // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long. }

void FIND_PEAK_INDEX() { // Finds the index of the major peak in the ZeroFFT maxvalue = 0; maxindex = 0; for (int i = 5; i < 128; i++) // Go through each element of the ZeroFFT (skip the DC peak) { if (ZeroFFT_lin_out[i] > maxvalue) // If the magnitude is larger than the previously seen maximum... { maxvalue = ZeroFFT_lin_out[i]; // ...store the new max... maxindex = i; // ...and the index at which it occurs. } } }

void KMAX() { // Calculates the spatial wavevector of the interferogram corresponding // to the peak in the ZeroFFT. kmax = 2 * PI / 256 * maxindex; }

void PHASE_ANGLE() { // Calculates the complex phase angle of the ZeroFFT peak // NOTE: This function must be called BEFORE the ZeroFFT is calculated. Am = 0; Bm = 0; for (int i = 0; i < 256; i++) // Calculate the real and imag Fourier components { Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part Bm = Bm + float ((ZeroFFT_input[2 * i]) * sin(kmax * i)); //magnitude of imaginary part } theta = atan2(Bm, Am); // Complext phase angle (in radians) }

void WRAPPING() { // Determines if a phase wrap/unwrap occured and accounts for it if ((preTheta ) > (0.5 * PI) && (theta) < (-0.7 * PI)) { // Compare the previous theat to the current theta to see if a wrap occured. Nwrap = Nwrap + 1; // If so, add 1 to the number of wraps. } if ((preTheta) < (-0.7 * PI) && (theta) > (0.5 * PI)) { // If an unwrap occured (a phase wrap in the other direction)... Nwrap = Nwrap - 1; // ...then subtract 1 from the number of wraps. } preTheta = theta; // Store the current theta for the next cycle }

void DISPLACEMENT() { // Calculate the displacement after the phase angle is determined m = 2 * PI * Nwrap; //M = theta + m; displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (1 / sqrt(2))) - predisplacement; //displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (0.80)) - predisplacement; }

// Servo Functions

void PID_LOOP() { // Performs feedback signal for PID control error = Setpoint - displacement;

// Store the current error signal; overwrite if necessary if( jerr >= MERR ){ jerr = 0; } elist[jerr] = error; jerr++;

// Calculate the running RMS error runningRMSerror = 0; for(int i=0; i<MERR; i++) { runningRMSerror += pow(elist[i],2); } runningRMSerror = sqrt(runningRMSerror/MERR);

// Calculate the mean-squared and root-mean-square errors over all time MSerror = (k - 1) / k * MSerror + pow(error, 2) / k; RMSerror = sqrt(MSerror); k = k + 1;

// Integral of error over all time esum = esum + error;

// Derivative of error time0 = millis(); D = (error - preverror) / (time0 - lastTime);

// The feedback signal (in millivolts) // The minus signs are to make sure the piezo moves in the right direction Output = -(kp * error) -(ki * esum) -(kd * D);

// Send the feedback to the DAC if PID_ON is 1 /*if (PID_ON) { val = offset + Output; val = max(val, 0); // Constrain the output voltage so that is stays in range val = min(val, 4096); DAC_TRANSFER(); }

// Save the current time and error for calc'ing the derivative next cycle lastTime = time0; preverror = error;*/ }

void SERIAL_PRINT(){

Serial.print(displacement); Serial.print(" , "); Serial.println(millis()); Serial.print(" ") ; }

/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void READ_PHOTO()': DIS_SET_V04_Arduino-zero:144: error: 'ZeroFFT_input' was not declared in this scope ZeroFFT_input[2 * i] = analogRead(AOpin0); // Output of first half of photodiode array ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void DO_ZeroFFT()': DIS_SET_V04_Arduino-zero:186: error: 'ZeroFFT_reorder' was not declared in this scope ZeroFFT_reorder(); // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used ^ DIS_SET_V04_Arduino-zero:187: error: 'ZeroFFT_run' was not declared in this scope ZeroFFT_run(); // This is the function that actually does the ZeroFFT ^ DIS_SET_V04_Arduino-zero:188: error: 'ZeroFFT_mag_lin' was not declared in this scope ZeroFFT_mag_lin(); // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long. ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void FIND_PEAK_INDEX()': DIS_SET_V04_Arduino-zero:196: error: 'ZeroFFT_lin_out' was not declared in this scope if (ZeroFFT_lin_out[i] > maxvalue) ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void PHASE_ANGLE()': DIS_SET_V04_Arduino-zero:217: error: 'ZeroFFT_input' was not declared in this scope Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part ^ exit status 1 'ZeroFFT_input' was not declared in this scope /Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/mic_tft/mic_tft.ino /Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/normalized/normalized.ino

#define LIN_OUT 1   // Include the resources for the linear output function
#define Adafruit_ZeroFFT 256  // Sets the ZeroFFT length to 256 points
#define MERR 10     // Number of error values to store in elist[MERR]
#define PID_ON 1    // Use PID feedback or not
#define TRI_PERIOD 100 // Half-period of triangle wave in loops
#define F_BLACKMAN 0.02463994238109641755656975202572 // Osillation freq. for Blackman filter
#define ARM_MATH_CM0PLUS    
#include <arm_common_tables.h>
#include <arm_math.h>
#include <Adafruit_ZeroFFT.h>
#include <SPI.h>

// Photodiode array variables

byte CLKpin = 4;    // Arduino pin delivering the clock pulses to pin 3 (CLK) of the TSL1402R
byte SIpin = 5;     // Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1402R
byte AOpin0 = A1;    // Arduino pin connected to pin 4 (analog output 1)of the TSL1402R
byte AOpin1 = A2;    // Arduino pin connected to pin 8 (analog output 2)of the TSL1402R

// Variables for determining the displacment from the ZeroFFT

int maxindex;       // Index of the maximum of the ZeroFFT
float maxvalue;     // For comparing the values of the ZeroFFT to find the global maximum
double kmax;        // Spatial wavenumber corresponding to the dominant fringe modulation Fourier component
float Am;           // Real part of Fourier coefficent corresponding to kmax
float Bm;           // Imag part of Fourier coefficent corresponding to kmax
float theta;        // Phase angle of Fourier transform at kmax
float preTheta = 0; // Storage for previous value of phase angle
int Nwrap = 0;      // Number of phase wraps
float displacement; // Displacement in nanometers
float predisplacement; // Storage for initial value of displacement
int w = 0;
int prevw = 0;
int wdiff = 0;

// PID Variables

unsigned long lastTime;
double Output=0;  // Output value for PID (voltage to the piezoelectric actuator (in millivolts))
double Setpoint;  // Desired value of displacement (in nm)
double kp = 0 / 1;    // 0 proportional gain for PID
double ki = 2/1;  // (1000 / (138.5)) integral gain for PID
//double ki = 2/ 1;  // (1000 / (138.5)) integral gain for PID
double kd = 0/ 100;    // 0 derivative gain for PID
double error;     // Error signal; difference between setpoint and displacement (in nm)
double preverror; // Stores previous value of error for derivative control
float esum;       // Integral of error signal over time
float D;          // Derivative of error signal
unsigned long time0 = 0; // Used in calculating the derivative term
float MSerror = 0;  // Mean squared error
float RMSerror = 0; // Root mean squared error
float elist[MERR];// Array of last MERR error values
int jerr = 0;        // index of integral error term
float runningRMSerror = 0; // RMS error calc'd from elist

float m = 0;      // extra variables for one time calculations
float pchange = 0;
float lastp = 0;
float k = 1;
int p = 1;
float M = 0;
//int switchtime = 1200; // Time (in ms) between Setpoint switches

void setup() {
  Serial.begin(9600); // Initialize serial interface to computer (i.e. serial monitor or plotter)
  INIT_PHOTO();       // Initialize the photodiode array
  READ_PHOTO();       // Read the photodiode array
  DO_ZeroFFT();           // Calculate the ZeroFFT of the photodiode array data
  FIND_PEAK_INDEX();  // Determine index of peak in ZeroFFT
  KMAX();             // Calculate spatial wavevector of the interferogram
  INIT_PHOTO();       // Maybe could be replaced by START_EXPOSURE()
  READ_PHOTO();       // Read photodiode again in preparation for next step
  PHASE_ANGLE();      // Calculate the complex phase angle of the ZeroFFT peak
  DISPLACEMENT();     // Calculate the displacement from the phase angle
  predisplacement = displacement; // Save the initial displacement corresponding to center of PZT range
  Setpoint = 0;       // Define the initial setpoint
  delay(100);         // Allow things to settle before beginning loop
  START_EXPOSURE();   // Turn on the photodiode array and begin integrating
}

void loop() {
  KMAX();                 // Calculate kmax from previous cycle's ZeroFFT
  READ_PHOTO();           // Read photodiode array
  PHASE_ANGLE();          // Calculate complex phase angle corresponding to kmax peak
  WRAPPING();            // Determine if a phase wrap occurred
  DISPLACEMENT();        // Calculate the displacement from the unwrapped phase
  DO_ZeroFFT();              // Calculate the ZeroFFT of the photodiode array data
  FIND_PEAK_INDEX();       // Determine index of peak in ZeroFFT
  //OSC_SET();             // Oscillate the setpoint up and down
  PID_LOOP();              // Perform feedback to follow the setpoint (if PID_ON is set to 1)
  //OSC_DAC();               // Send an oscillating voltage to the DAC
  //TRI_DAC();              // Send a triangular wave voltage to the DAC
  START_EXPOSURE();          // Turn on the photodiode array and begin integrating for next cycle
  SERIAL_PRINT();               // Print some outputs to the serial USB port
}

// Photodiode functions 

void ClockPulse() { // For sending clock pulses during reading of photodiode
  delayMicroseconds(1);
  digitalWrite(CLKpin, HIGH);
  digitalWrite(CLKpin, LOW);
}

void INIT_PHOTO() { // Intialization of photodiode
  // Initialize two Arduino pins as digital output:
    pinMode(CLKpin, OUTPUT);
    pinMode(SIpin, OUTPUT);
  // To set up the ADC, first remove bits set by Arduino library, then choose
 
    for ( int i = 0; i < 14; i++ )
    {
      digitalWrite(i, LOW);
    }
  // Clock out any existing SI pulse through the ccd register:
    for (int i = 0; i < 260; i++)
    {
      ClockPulse();
    }
  // Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    ClockPulse();
    digitalWrite(SIpin, LOW);
    for (int i = 0; i < 260; i++)
    {
      ClockPulse();
    }
}

void READ_PHOTO() { // Read the photodiode
  
  // Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse
  // into the sensors register:
  digitalWrite(SIpin, HIGH);
  ClockPulse();
  digitalWrite(SIpin, LOW);

  // Next, read all 256 pixels in parallel. Store the result in the array. Each clock pulse
  // causes a new pixel to expose its value on the two outputs:
  for (int i = 0; i < 128; i++)
  {
    delayMicroseconds(20);  // We add a delay to stabilize the AO output from the sensor
    ZeroFFT_input[2 * i] = analogRead(AOpin0);        // Output of first half of photodiode array
    ZeroFFT_input[2 * i + 1] = 0;                     // Store zero in the "imaginary" part of the array
    ZeroFFT_input[2 * i + 256] = analogRead(AOpin1);  // Output of second half of photodiode array
    ZeroFFT_input[2 * i + 257] = 0;                   // Store zero in the "imaginary" part of the array
    ClockPulse();
  }

  // Next, AGAIN stop the ongoing integration of light quanta from each photodiode 
  // by clocking in a SI pulse. This is necessary because during the readout operation,
  // the 18th clock pulse starts the integration of light intensity again.
  // This way we can turn on the integration when we want using the START_EXPOSURE() command.
  digitalWrite(SIpin, HIGH);
  ClockPulse();
  digitalWrite(SIpin, LOW);

  // The photodiode remains OFF after this function completes.
  // Call START_EXPOSURE() to turn on the photodiode array and begin integrating.
}

void START_EXPOSURE() { 
  // The photodiode array starts integrating once 18 clock pulses have passed. 
  // At that time, the photodiodes are once again active. We clock out the SI pulse through
  // the 256 bit register in order to be ready to halt the ongoing measurement at our will
  // (by clocking in a new SI pulse):
  // To be used after all calculations are finished, but 
  // before the next photodiode read operation.
  for (int i = 0; i < 260; i++)
  {
    if (i == 18)
    {
      // Now the photodiodes goes active..
      // An external trigger can be placed here
    }
    ClockPulse();
  }
  // Uncomment the next line to increase the integration time.
  //delay(15);// <-- Add 15 ms integration time
}

//Calculation Functions 

void DO_ZeroFFT() {  // Performs the ZeroFFT
  ZeroFFT_reorder();  // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used
  ZeroFFT_run();      // This is the function that actually does the ZeroFFT
  ZeroFFT_mag_lin();  // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long.
}

void FIND_PEAK_INDEX() { // Finds the index of the major peak in the ZeroFFT
  maxvalue = 0;
  maxindex = 0;
  for (int i = 5; i < 128; i++) // Go through each element of the ZeroFFT (skip the DC peak)
  {
    if (ZeroFFT_lin_out[i] > maxvalue) 
    // If the magnitude is larger than the previously seen maximum...
    {
      maxvalue = ZeroFFT_lin_out[i]; // ...store the new max...
      maxindex = i;              // ...and the index at which it occurs.
    }
  }
}

void KMAX() { 
  // Calculates the spatial wavevector of the interferogram corresponding 
  // to the peak in the ZeroFFT.
  kmax = 2 * PI / 256 * maxindex;
}

void PHASE_ANGLE() { // Calculates the complex phase angle of the ZeroFFT peak
  // NOTE: This function must be called BEFORE the ZeroFFT is calculated.
  Am = 0;
  Bm = 0;
  for (int i = 0; i < 256; i++) // Calculate the real and imag Fourier components
  {
    Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part
    Bm = Bm + float ((ZeroFFT_input[2 * i]) * sin(kmax * i)); //magnitude of imaginary part
  }
  theta = atan2(Bm, Am); // Complext phase angle (in radians)
}

void WRAPPING() { // Determines if a phase wrap/unwrap occured and accounts for it
  if ((preTheta ) > (0.5 * PI) && (theta) < (-0.7 * PI)) {
    // Compare the previous theat to the current theta to see if a wrap occured.
    Nwrap = Nwrap + 1; // If so, add 1 to the number of wraps.
  }
  if ((preTheta) < (-0.7 * PI) && (theta) > (0.5 * PI)) {
    // If an unwrap occured (a phase wrap in the other direction)...
    Nwrap = Nwrap - 1; // ...then subtract 1 from the number of wraps.
  }
  preTheta = theta; // Store the current theta for the next cycle
}

void DISPLACEMENT() { // Calculate the displacement after the phase angle is determined
  m =   2 * PI * Nwrap;
  //M = theta + m;
  displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (1 / sqrt(2))) - predisplacement;
  //displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (0.80)) - predisplacement;
}

// Servo Functions

void PID_LOOP() { // Performs feedback signal for PID control
  error = Setpoint - displacement;

  // Store the current error signal; overwrite if necessary
  if( jerr >= MERR ){
    jerr = 0;
  }
  elist[jerr] = error;
  jerr++;

  // Calculate the running RMS error
  runningRMSerror = 0;
  for(int i=0; i<MERR; i++) {
    runningRMSerror += pow(elist[i],2);
  }
  runningRMSerror = sqrt(runningRMSerror/MERR);
  
  // Calculate the mean-squared and root-mean-square errors over all time
  MSerror = (k - 1) / k * MSerror + pow(error, 2) / k; 
  RMSerror = sqrt(MSerror);
  k = k + 1;

  // Integral of error over all time
  esum = esum + error;
  
  // Derivative of error
  time0 = millis();
  D = (error - preverror) / (time0 - lastTime);
  
  // The feedback signal (in millivolts)
  // The minus signs are to make sure the piezo moves in the right direction
  Output = -(kp * error) -(ki * esum) -(kd * D);

  // Send the feedback to the DAC if PID_ON is 1
  /*if (PID_ON) {
    val = offset + Output;
    val = max(val, 0);    // Constrain the output voltage so that is stays in range 
    val = min(val, 4096);
    DAC_TRANSFER();
  }

  // Save the current time and error for calc'ing the derivative next cycle
  lastTime = time0;
  preverror = error;*/
}

void SERIAL_PRINT(){
  
  Serial.print(displacement);
  Serial.print(" , ");
  Serial.println(millis());
  Serial.print(" ") ; 
}
/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void READ_PHOTO()':
DIS_SET_V04_Arduino-zero:144: error: 'ZeroFFT_input' was not declared in this scope
     ZeroFFT_input[2 * i] = analogRead(AOpin0);        // Output of first half of photodiode array
     ^
/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void DO_ZeroFFT()':
DIS_SET_V04_Arduino-zero:186: error: 'ZeroFFT_reorder' was not declared in this scope
   ZeroFFT_reorder();  // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used
                   ^
DIS_SET_V04_Arduino-zero:187: error: 'ZeroFFT_run' was not declared in this scope
   ZeroFFT_run();      // This is the function that actually does the ZeroFFT
               ^
DIS_SET_V04_Arduino-zero:188: error: 'ZeroFFT_mag_lin' was not declared in this scope
   ZeroFFT_mag_lin();  // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long.
                   ^
/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void FIND_PEAK_INDEX()':
DIS_SET_V04_Arduino-zero:196: error: 'ZeroFFT_lin_out' was not declared in this scope
     if (ZeroFFT_lin_out[i] > maxvalue) 
         ^
/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void PHASE_ANGLE()':
DIS_SET_V04_Arduino-zero:217: error: 'ZeroFFT_input' was not declared in this scope
     Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part
                       ^
exit status 1
'ZeroFFT_input' was not declared in this scope
/Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/mic_tft/mic_tft.ino
/Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/normalized/normalized.ino
Source Link

How to change the FFT function of the Arduino Uno for the Arduino Zero?

#define LIN_OUT 1 // Include the resources for the linear output function #define Adafruit_ZeroFFT 256 // Sets the ZeroFFT length to 256 points #define MERR 10 // Number of error values to store in elist[MERR] #define PID_ON 1 // Use PID feedback or not #define TRI_PERIOD 100 // Half-period of triangle wave in loops #define F_BLACKMAN 0.02463994238109641755656975202572 // Osillation freq. for Blackman filter #define ARM_MATH_CM0PLUS
#include <arm_common_tables.h> #include <arm_math.h> #include <Adafruit_ZeroFFT.h> #include <SPI.h>

// Photodiode array variables

byte CLKpin = 4; // Arduino pin delivering the clock pulses to pin 3 (CLK) of the TSL1402R byte SIpin = 5; // Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1402R byte AOpin0 = A1; // Arduino pin connected to pin 4 (analog output 1)of the TSL1402R byte AOpin1 = A2; // Arduino pin connected to pin 8 (analog output 2)of the TSL1402R

// Variables for determining the displacment from the ZeroFFT

int maxindex; // Index of the maximum of the ZeroFFT float maxvalue; // For comparing the values of the ZeroFFT to find the global maximum double kmax; // Spatial wavenumber corresponding to the dominant fringe modulation Fourier component float Am; // Real part of Fourier coefficent corresponding to kmax float Bm; // Imag part of Fourier coefficent corresponding to kmax float theta; // Phase angle of Fourier transform at kmax float preTheta = 0; // Storage for previous value of phase angle int Nwrap = 0; // Number of phase wraps float displacement; // Displacement in nanometers float predisplacement; // Storage for initial value of displacement int w = 0; int prevw = 0; int wdiff = 0;

// PID Variables

unsigned long lastTime; double Output=0; // Output value for PID (voltage to the piezoelectric actuator (in millivolts)) double Setpoint; // Desired value of displacement (in nm) double kp = 0 / 1; // 0 proportional gain for PID double ki = 2/1; // (1000 / (138.5)) integral gain for PID //double ki = 2/ 1; // (1000 / (138.5)) integral gain for PID double kd = 0/ 100; // 0 derivative gain for PID double error; // Error signal; difference between setpoint and displacement (in nm) double preverror; // Stores previous value of error for derivative control float esum; // Integral of error signal over time float D; // Derivative of error signal unsigned long time0 = 0; // Used in calculating the derivative term float MSerror = 0; // Mean squared error float RMSerror = 0; // Root mean squared error float elist[MERR];// Array of last MERR error values int jerr = 0; // index of integral error term float runningRMSerror = 0; // RMS error calc'd from elist

float m = 0; // extra variables for one time calculations float pchange = 0; float lastp = 0; float k = 1; int p = 1; float M = 0; //int switchtime = 1200; // Time (in ms) between Setpoint switches

void setup() { Serial.begin(9600); // Initialize serial interface to computer (i.e. serial monitor or plotter) INIT_PHOTO(); // Initialize the photodiode array READ_PHOTO(); // Read the photodiode array DO_ZeroFFT(); // Calculate the ZeroFFT of the photodiode array data FIND_PEAK_INDEX(); // Determine index of peak in ZeroFFT KMAX(); // Calculate spatial wavevector of the interferogram INIT_PHOTO(); // Maybe could be replaced by START_EXPOSURE() READ_PHOTO(); // Read photodiode again in preparation for next step PHASE_ANGLE(); // Calculate the complex phase angle of the ZeroFFT peak DISPLACEMENT(); // Calculate the displacement from the phase angle predisplacement = displacement; // Save the initial displacement corresponding to center of PZT range Setpoint = 0; // Define the initial setpoint delay(100); // Allow things to settle before beginning loop START_EXPOSURE(); // Turn on the photodiode array and begin integrating }

void loop() { KMAX(); // Calculate kmax from previous cycle's ZeroFFT READ_PHOTO(); // Read photodiode array PHASE_ANGLE(); // Calculate complex phase angle corresponding to kmax peak WRAPPING(); // Determine if a phase wrap occurred DISPLACEMENT(); // Calculate the displacement from the unwrapped phase DO_ZeroFFT(); // Calculate the ZeroFFT of the photodiode array data FIND_PEAK_INDEX(); // Determine index of peak in ZeroFFT //OSC_SET(); // Oscillate the setpoint up and down PID_LOOP(); // Perform feedback to follow the setpoint (if PID_ON is set to 1) //OSC_DAC(); // Send an oscillating voltage to the DAC //TRI_DAC(); // Send a triangular wave voltage to the DAC START_EXPOSURE(); // Turn on the photodiode array and begin integrating for next cycle SERIAL_PRINT(); // Print some outputs to the serial USB port }

// Photodiode functions

void ClockPulse() { // For sending clock pulses during reading of photodiode delayMicroseconds(1); digitalWrite(CLKpin, HIGH); digitalWrite(CLKpin, LOW); }

void INIT_PHOTO() { // Intialization of photodiode // Initialize two Arduino pins as digital output: pinMode(CLKpin, OUTPUT); pinMode(SIpin, OUTPUT); // To set up the ADC, first remove bits set by Arduino library, then choose

for ( int i = 0; i < 14; i++ )
{
  digitalWrite(i, LOW);
}

// Clock out any existing SI pulse through the ccd register: for (int i = 0; i < 260; i++) { ClockPulse(); } // Create a new SI pulse and clock out that same SI pulse through the sensor register: digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW); for (int i = 0; i < 260; i++) { ClockPulse(); } }

void READ_PHOTO() { // Read the photodiode

// Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse // into the sensors register: digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW);

// Next, read all 256 pixels in parallel. Store the result in the array. Each clock pulse // causes a new pixel to expose its value on the two outputs: for (int i = 0; i < 128; i++) { delayMicroseconds(20); // We add a delay to stabilize the AO output from the sensor ZeroFFT_input[2 * i] = analogRead(AOpin0); // Output of first half of photodiode array ZeroFFT_input[2 * i + 1] = 0; // Store zero in the "imaginary" part of the array ZeroFFT_input[2 * i + 256] = analogRead(AOpin1); // Output of second half of photodiode array ZeroFFT_input[2 * i + 257] = 0; // Store zero in the "imaginary" part of the array ClockPulse(); }

// Next, AGAIN stop the ongoing integration of light quanta from each photodiode // by clocking in a SI pulse. This is necessary because during the readout operation, // the 18th clock pulse starts the integration of light intensity again. // This way we can turn on the integration when we want using the START_EXPOSURE() command. digitalWrite(SIpin, HIGH); ClockPulse(); digitalWrite(SIpin, LOW);

// The photodiode remains OFF after this function completes. // Call START_EXPOSURE() to turn on the photodiode array and begin integrating. }

void START_EXPOSURE() { // The photodiode array starts integrating once 18 clock pulses have passed. // At that time, the photodiodes are once again active. We clock out the SI pulse through // the 256 bit register in order to be ready to halt the ongoing measurement at our will // (by clocking in a new SI pulse): // To be used after all calculations are finished, but // before the next photodiode read operation. for (int i = 0; i < 260; i++) { if (i == 18) { // Now the photodiodes goes active.. // An external trigger can be placed here } ClockPulse(); } // Uncomment the next line to increase the integration time. //delay(15);// <-- Add 15 ms integration time }

//Calculation Functions

void DO_ZeroFFT() { // Performs the ZeroFFT ZeroFFT_reorder(); // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used ZeroFFT_run(); // This is the function that actually does the ZeroFFT ZeroFFT_mag_lin(); // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long. }

void FIND_PEAK_INDEX() { // Finds the index of the major peak in the ZeroFFT maxvalue = 0; maxindex = 0; for (int i = 5; i < 128; i++) // Go through each element of the ZeroFFT (skip the DC peak) { if (ZeroFFT_lin_out[i] > maxvalue) // If the magnitude is larger than the previously seen maximum... { maxvalue = ZeroFFT_lin_out[i]; // ...store the new max... maxindex = i; // ...and the index at which it occurs. } } }

void KMAX() { // Calculates the spatial wavevector of the interferogram corresponding // to the peak in the ZeroFFT. kmax = 2 * PI / 256 * maxindex; }

void PHASE_ANGLE() { // Calculates the complex phase angle of the ZeroFFT peak // NOTE: This function must be called BEFORE the ZeroFFT is calculated. Am = 0; Bm = 0; for (int i = 0; i < 256; i++) // Calculate the real and imag Fourier components { Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part Bm = Bm + float ((ZeroFFT_input[2 * i]) * sin(kmax * i)); //magnitude of imaginary part } theta = atan2(Bm, Am); // Complext phase angle (in radians) }

void WRAPPING() { // Determines if a phase wrap/unwrap occured and accounts for it if ((preTheta ) > (0.5 * PI) && (theta) < (-0.7 * PI)) { // Compare the previous theat to the current theta to see if a wrap occured. Nwrap = Nwrap + 1; // If so, add 1 to the number of wraps. } if ((preTheta) < (-0.7 * PI) && (theta) > (0.5 * PI)) { // If an unwrap occured (a phase wrap in the other direction)... Nwrap = Nwrap - 1; // ...then subtract 1 from the number of wraps. } preTheta = theta; // Store the current theta for the next cycle }

void DISPLACEMENT() { // Calculate the displacement after the phase angle is determined m = 2 * PI * Nwrap; //M = theta + m; displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (1 / sqrt(2))) - predisplacement; //displacement = ((-(theta + m) * 632) * (1 / (4 * PI)) * (0.80)) - predisplacement; }

// Servo Functions

void PID_LOOP() { // Performs feedback signal for PID control error = Setpoint - displacement;

// Store the current error signal; overwrite if necessary if( jerr >= MERR ){ jerr = 0; } elist[jerr] = error; jerr++;

// Calculate the running RMS error runningRMSerror = 0; for(int i=0; i<MERR; i++) { runningRMSerror += pow(elist[i],2); } runningRMSerror = sqrt(runningRMSerror/MERR);

// Calculate the mean-squared and root-mean-square errors over all time MSerror = (k - 1) / k * MSerror + pow(error, 2) / k; RMSerror = sqrt(MSerror); k = k + 1;

// Integral of error over all time esum = esum + error;

// Derivative of error time0 = millis(); D = (error - preverror) / (time0 - lastTime);

// The feedback signal (in millivolts) // The minus signs are to make sure the piezo moves in the right direction Output = -(kp * error) -(ki * esum) -(kd * D);

// Send the feedback to the DAC if PID_ON is 1 /*if (PID_ON) { val = offset + Output; val = max(val, 0); // Constrain the output voltage so that is stays in range val = min(val, 4096); DAC_TRANSFER(); }

// Save the current time and error for calc'ing the derivative next cycle lastTime = time0; preverror = error;*/ }

void SERIAL_PRINT(){

Serial.print(displacement); Serial.print(" , "); Serial.println(millis()); Serial.print(" ") ; }

Hi every one. I tried to compile this code for the Arduino Zero which was originally written for the Arduino Uno. I got the following errors. What am I doing wrong?

Error:

/Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void READ_PHOTO()': DIS_SET_V04_Arduino-zero:144: error: 'ZeroFFT_input' was not declared in this scope ZeroFFT_input[2 * i] = analogRead(AOpin0); // Output of first half of photodiode array ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void DO_ZeroFFT()': DIS_SET_V04_Arduino-zero:186: error: 'ZeroFFT_reorder' was not declared in this scope ZeroFFT_reorder(); // Reorders the ZeroFFT_input array to allow the ZeroFFT_run() command to be used ^ DIS_SET_V04_Arduino-zero:187: error: 'ZeroFFT_run' was not declared in this scope ZeroFFT_run(); // This is the function that actually does the ZeroFFT ^ DIS_SET_V04_Arduino-zero:188: error: 'ZeroFFT_mag_lin' was not declared in this scope ZeroFFT_mag_lin(); // Produces a variable ZeroFFT_lin_out that contains the absolute values of the ZeroFFT, 128 elements long. ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void FIND_PEAK_INDEX()': DIS_SET_V04_Arduino-zero:196: error: 'ZeroFFT_lin_out' was not declared in this scope if (ZeroFFT_lin_out[i] > maxvalue) ^ /Users/RAJU/Documents/Documents/All Folders/Arduino 2017_v03_Maintable/Arduino-zero/DIS_SET_V04_Arduino-zero/DIS_SET_V04_Arduino-zero.ino: In function 'void PHASE_ANGLE()': DIS_SET_V04_Arduino-zero:217: error: 'ZeroFFT_input' was not declared in this scope Am = Am + float ((ZeroFFT_input[2 * i]) * cos(kmax * i)); //magnitude of real part ^ exit status 1 'ZeroFFT_input' was not declared in this scope /Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/mic_tft/mic_tft.ino /Users/RAJU/Documents/Arduino/libraries/Adafruit_Zero_FFT_Library/examples/normalized/normalized.ino