yash-sanghvi / ESP32

125 stars 61 forks source link

Turned your code into a Class / library #1

Open MichielfromNL opened 3 years ago

MichielfromNL commented 3 years ago

Hi, I was using ArduinoFFT sofar, and found your code when I was looking for a faster FFT for my project. Which worked fine, super!

I spend a few hours today to turn it into a class, added some functions to make it work just like ArduinoFFT and made it a tad more "user friendly". the zip installs as an arduino library Best regards, Michiel

ESPfft.zip


#define FFT_N       2048  // Must be a power of 2
#define SAMPLEFREQ  218   //

//#define TOTAL_TIME  9.391904 //The time in which data was captured. This is equal to FFT_N/sampling_freq

float fft_input[FFT_N];
float fft_output[FFT_N];

#include "ESP32_fft.h" // include the library
#include "fft_signal.h"

// class
ESP_fft FFT(FFT_N, SAMPLEFREQ, FFT_REAL, FFT_FORWARD, fft_input, fft_output);

void setup() {
  Serial.begin(115200); // use the serial port
  while (!Serial);
  Serial.println("Hello. FFT test");
  for (int k = 0 ; k < FFT_N ; k++)
    fft_input[k] = (float)fft_signal[k];

  long int t1 = micros();
  // Execute transformation
  FFT.removeDC();
  FFT.hammingWindow();
  FFT.execute();
  FFT.complexToMagnitude();
  long int t2 = micros();
  //FFT.print();
  Serial.print("Time taken: ");Serial.print((t2-t1)*1.0/1000);Serial.println(" milliseconds!");

  // Print the output
  Serial.println();
  /*Multiply the magnitude of the DC component with (1/FFT_N) to obtain the DC component*/
  Serial.printf("DC component : %f g\n", (fft_output[0])/FFT_N);  // DC is at [0]

  Serial.printf("Fundamental Freq : %f Hz\t Mag: %f g\n", FFT.majorPeakFreq(), (FFT.majorPeak()/10000)*2/FFT_N);
  for (int i=0; i< 10; i++) {
    Serial.printf("%f:%f\n", FFT.frequency(i),fft_output[i]);
  }

}

void loop() {

}```
yash-sanghvi commented 3 years ago

This is excellent @MichielfromNL. Thanks for the efforts. I'll add the links to this post of yours in the Readme, and also in the Medium tutorial on FFT onboard ESP32.

citamrac commented 3 years ago

I have tried this out with a frequency sweep , generated from my computer and input via my ESP32's ADC, and it seems that no matter the input frequency, only the highest frequency bins have the strongest peaks

sanghvi-yash commented 3 years ago

Can you share some more details on the input and output and also share code snippets?

Shnagarsheth commented 3 years ago

Thank you making it a Library; unfortunetly, I am receving errors for constructor. As I am not a master of C++ can you please help me with this

Error while Compiling

In file included from lib\ESPfft\ESP32_fft.cpp:31:0:
lib\ESPfft\ESP32_fft.h: In constructor 'ESP_fft::ESP_fft(int, int, fft_type_t, fft_direction_t, float*, float*)':
lib\ESPfft\ESP32_fft.h:75:19: error: 'ESP_fft::_direction' will be initialized after [-Werror=reorder]
   fft_direction_t _direction;     // forward or backward
                   ^
lib\ESPfft\ESP32_fft.h:71:19: error:   'float* ESP_fft::_input' [-Werror=reorder]
   float        *  _input;         // pointer to input buffer
                   ^
lib\ESPfft\ESP32_fft.cpp:37:1: error:   when initialized here [-Werror=reorder]
 ESP_fft::ESP_fft(int size, int samplefreq,fft_type_t type, fft_direction_t direction, float input[], float output[]) :      
 ^
cc1plus.exe: some warnings being treated as errors
MichielfromNL commented 3 years ago

Thank you making it a Library; unfortunetly, I am receving errors for constructor. As I am not a master of C++ can you please help me with this

I suspect the compiler flag [-Werror=reorder] triggers , because the order of class variables in the header file is not exactly as the order of the initaliser list in the constructor. I don't have the possibility here to test the fix, but you may want to try changing the order of variables in the ESP_fft.h:

It is now: private: int _size; // FFT size
int _samplefreq;
float _binwidth; // freq per bin
float _input; // pointer to input buffer
float
_output; // pointer to output buffer
float * _twiddle_factors; // pointer to buffer holding twiddle factors fft_type_t _type; // real or complex fft_direction_t _direction; // forward or backward unsigned int _flags; // FFT flags float _max_mag = 0; float _fundamental_freq = 0;

Change it into:

private: int _size; // FFT size int _samplefreq; fft_type_t _type; // real or complex fft_direction_t _direction; // forward or backward float _input; // pointer to input buffer float _output; // pointer to output buffer float * _twiddle_factors; // pointer to buffer holding twiddle factors float _binwidth; // freq per bin unsigned int _flags; // FFT flags float _max_mag = 0; float _fundamental_freq = 0;

Hope this helps

Shnagarsheth commented 3 years ago

Thank you for your prompt reply. It worked; no compilation Error now.

be-engineer commented 2 years ago

Nice job, great! By the way,can I use directly output value to show in LCD? Does the output value represent the amplitude of the corresponding frequency?

Spartrap commented 2 years ago

@MichielfromNL thank you for your effort to make this code more object-oriented, it's very much appreciated.

OTOH, I believe there is a mistake in the definition of the _binwidth member (and consequently, the output of the frequency() method is likely wrong): _binwidth = (float)_samplefreq/(_size/2.0);

I believe it should read simply "(float) samplefreq /_size;", as only half the sampling frequency bandwidth is available (Nyquist theorem), so the 2.0 gets simplified away.. Best regards.

diplab-projects commented 2 years ago

@MichielfromNL thank you very much for your effort.

FYI, there is a problem in the implementation of the function complexToMagnitude. After calculating _max_mag and _fundamental_freq, these values will never be updated if the new values aren't bigger.

I fixed locally this behavior by resetting them in each call of complexToMagnitude.

https://gist.github.com/diplab-projects/8551fa44b44abf5a35ec8a16681761fa


Oh, and BTW:

OTOH, I believe there is a mistake in the definition of the _binwidth member (and consequently, the output of the frequency() method is likely wrong): _binwidth = (float)_samplefreq/(_size/2.0);

I believe it should read simply "(float) samplefreq /_size;", as only half the sampling frequency bandwidth is available (Nyquist theorem), so the 2.0 gets simplified away.. Best regards.

You are absolutely right. I tested this with real data, and the frequency will be doubled.

DanieljVargas commented 2 months ago

Can anyone give a snippet or some help to use the library with input in ADC? Im trying to use it with current and voltage sensors so I can get the amplitudes of the harmonics. But it isnt working right. Thanks