How to use =========== .. toctree:: :maxdepth: 3 :caption: Contents: Platform support ---------------- This library does not contain any external dependency and can be used on any platform that supports C++11. It is composed of a header and a static `.a` libary provided for the following platforms: - `Linux` - `Windows` - `MacOs apple silicon` - `Esp32s3` - `Teensy4.X` .. note:: If you need a precompiled version for another platform, please contact us at `CONTACT `_ . We will be happy to provide it in the next release! Processing times examples for microcontrollers: +------------------------+----------------------------------------+-----------------------------------------------+ | Size / microcontroller | ESP32-S3(-O2): proc time (max FFT freq)|Teensy4X (OPT_faster): proc time (max FFT freq)| +========================+========================================+===============================================+ | 64 | 100us (10kHz) | 15us (66kHz) | +------------------------+----------------------------------------+-----------------------------------------------+ | 128 | 175us (5.7kHz) |30us (33kHz) | +------------------------+----------------------------------------+-----------------------------------------------+ | 256 | 325us (3kHz) |61us (16kHz) | +------------------------+----------------------------------------+-----------------------------------------------+ | 512 | 650us (1.5kHz) | 126us (8kHz) | +------------------------+----------------------------------------+-----------------------------------------------+ | 1024 | 1290us (775Hz) |262us (3.8kHz) | +------------------------+----------------------------------------+-----------------------------------------------+ | 2048 | 2630us (380Hz) |540us (1.85kHz) | +------------------------+----------------------------------------+-----------------------------------------------+ | 4096 | 5390us (185Hz) |1240us (800Hz) | +------------------------+----------------------------------------+-----------------------------------------------+ .. tip:: The possibility to build the library on embedded device and on host computer allows for quick development and easy tuning of the parameters using replays of real data! Usage --------- 1. Select configurations ~~~~~~~~~~~~~~~~~~~~~~~~~~ In the project used, the `.ini` (generally platformio.ini) file has to provide the compilation configuration, depending on the FFT size. The configuration include the header path (using -I), and the static précompiled static library adapted to the platform used (using -L and -l). .. admonition:: example For example with a 256 FFT size for an ESP32-S3, the following lines have to be added in the `.ini` file: .. code-block:: ini :linenos: build_flags = -O2 -DBOARD_HAS_PSRAM ... -I lib/libDM_SRX_fft/src/model_fft256/ -L lib/libDM_SRX_fft/src/static_libs -l SrxFFT256_esp32s3.a 2. Create and initialize object ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. important:: API ref: :cpp:class:`SRX_MODEL_FFT`, :cpp:func:`SRX_MODEL_FFT::initialize` After the inclusion, create the stepable object. Here we choose a FFT size (window) of 256 samples: .. code-block:: c++ #include "libDM_SRX_FFT256_interface.hpp" SRX_MODEL_FFT fft; In any function that is executed one time before loop (setup for arduino ...): .. code-block:: c++ fft.initialize(); 2. Initialize inputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. important:: API ref: :cpp:class:`SRX_MODEL_FFT`, :cpp:class:`SRX_MODEL_FFT::modelInputs`, :cpp:func:`SRX_MODEL_FFT::setInputs` Before the while loop, create a modelInputs object: .. code-block:: c++ SRX_MODEL_FFT::modelInputs fftInputs = SRX_MODEL_FFT::modelInputs(); 3. Feed the model and step it ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. important:: API ref: :cpp:func:`SRX_MODEL_FFT::setInputs`, :cpp:func:`SRX_MODEL_FFT::step` The library handles the buffering of the inputs, so the idea is not to feed it with a table. Just feed it with a single value at each loop iteration. In the while loop, feed the FFT object with the inputs and step it: For example, with an accelerometer output (for more informations about sensors reading, see : `libDM_icm42688 doc `_): .. code-block:: c++ :linenos: // Get sensors data icm.readFifo(); resIMU = icm.getOutput(); // Set accelerometer Z acceleration as FFT input fftInputs.signalInput = resIMU.gAccelData[2]; fft.setInputs(fftInputs); fft.step(); 4. Get outputs ~~~~~~~~~~~~~~~~ .. important:: :cpp:class:`SRX_MODEL_FFT::modelOutputs`, :cpp:func:`SRX_MODEL_FFT::getOutputs` After the step, outputs specified in :cpp:class:`SRX_MODEL_FFT::modelOutputs` will be updated and can be retrieved with accessing the pointer content. For example to print the FFT vector obtained: .. code-block:: c++ :linenos: for (size_t i = 0; i < 128; i++) { Serial.println("FFT[" + String(i) + "] = " + String(fft.getOutputs().fftVector[i])); } Decode FFT results ------------------- The FFT vector output gets arbitrary frequency axis. To link these values to physical frequency, the input signal sampling rate has to be known. As the buffering is included, the way to use the class is to call step() at constant rate, and getting the output fft vector when needed. The corresponding frequency is given by the step of the FFT (ie: 500Hz application using a 256 size FFT, the block will output a vector with a size of 128. To get the frequency associated with the vector, you must do step=500/256, the vector is graduated this way : vect = [0:step:500/2-step] = [0 1.95 3.9 ... 247.65] Hz .. math:: \text{vect} = [0, 1.95, 3.9, \ldots, 247.65] \text{ Hz} Example of use on virtual signal with a 256 size FFT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Example 1 ^^^^^^^^^ We will generate a virtual signal with a sampling rate of 100Hz. This signal will be compose of a 10Hz frequency sine wave with an amplitude of 2, and a 20Hz frequency sine wave with an amplitude of 1: .. code-block:: c++ :linenos: #include "libDM_SRX_FFT256_interface.hpp" SRX_MODEL_FFT fft; void setup() { fft.initialize(); SRX_MODEL_FFT::modelInputs fftInputs = SRX_MODEL_FFT::modelInputs(); while (curTime < 5.F) { // Generate a virtual signal (2 sine waves at 10Hz and 50hz frequency, with 2 and 1 values for amplitude) float curSin = 2 * std::sin(2 * 3.14 * 10 * curTime) + 1 * std::sin(2 * 3.14 * 20 * curTime); fftInputs.signalInput = curSin; fft.setInputs(fftInputs); fft.step(); curTime += 0.01F; // 100Hz sampling rate } // Print the FFT vector and associated frequency float step = 100.F/256.F; for (size_t i = 0; i < 128; i++) { Serial.println("Amplitude[" + String(step * i) + "] = " + String(fft.getOutputs().fftVector[i])); } } .. image:: images/FFT1.png :height: 400px :align: center Of course the result is not so precise, lets try with a 1024 size FFT! Example 2 ^^^^^^^^^ First we modify the compilation options in the `.ini` file to use a 2048 size FFT: .. code-block:: ini :linenos: build_flags = -O2 -DBOARD_HAS_PSRAM ... -I lib/libDM_SRX_fft/src/model_fft2048/ -L lib/libDM_SRX_fft/src/static_libs -l SrxFFT2048_esp32s3.a We then include the correct header and modify a little the options. The sampling frequency will now be 250Hz: .. code-block:: c++ :linenos: #include "libDM_SRX_FFT2048_interface.hpp" SRX_MODEL_FFT fft; void setup() { fft.initialize(); SRX_MODEL_FFT::modelInputs fftInputs = SRX_MODEL_FFT::modelInputs(); while (curTime < 10.F) // 10 seconds is enough to fill 2500 samples, perfect for 2048 size FFT { // Generate a virtual signal (2 sine waves at 10Hz and 50hz frequency, with 2 and 1 values for amplitude) float curSin = 2 * std::sin(2 * 3.14 * 10 * curTime) + 1 * std::sin(2 * 3.14 * 20 * curTime); fftInputs.signalInput = curSin; fft.setInputs(fftInputs); fft.step(); curTime += 0.004F; // 250Hz sampling rate } // Print the FFT vector and associated frequency float step = 250.F/2048.F; for (size_t i = 0; i < 512; i++) { Serial.println("Amplitude[" + String(step * i) + "] = " + String(fft.getOutputs().fftVector[i])); } } We got a more precise result: amplitude is more precisely detected, resolution is improved, and we could theoretically detect up to 125Hz frequency signals, compared to 50Hz in the previous example. .. image:: images/FFT3.png :height: 200px :align: center .. image:: images/FFT2.png :height: 200px :align: center .. image:: images/ResultsFFT.png :width: 1000px :align: center The matching between the sampling frequency and the FFT windows size has to be taken into account to get the best results, depending on the signals to be analyzed. Of course the FFT computation time is the primary factor to take into account when choosing sampling frequency!