logo elektroda
logo elektroda
X
logo elektroda

FFT in practice using ESP32 and Arduino.

TechEkspert 22203 11
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
  • FFT in practice using ESP32 and Arduino.
    In the material you will find an introduction to the Fourier transform with the theory kept to a minimum. It is a proposal to get acquainted with the topic through practical experiments, then an intuitive sense of what FFT can be useful for. If you are put off by complicated math, this material may be helpful. If mathematics is your element, remember that I will deliberately skip and simplify a lot of things, assuming that you have to start with something and then you can look further on your own. For the experiments we will use the Arduino environment, ESP32 and a monochrome LCD 128x64px display equipped with an SPI bus. The ESP32 module was available in the elektroda.pl gadgets, information on how to configure the Arduino environment to work with ESP32 can be found here: configuration of the Wi-Fi and Bluetooth ESP32 module in Arduino .
    In the material you will find photos and videos presenting the results, there is also the code of the program used, which will facilitate your own practical tests.
    Fourier transformation allows you to move from the time domain (in practice, for example, a buffer with samples from the ADC - an analog-to-digital converter, downloaded at a specific frequency) to the frequency domain, i.e. in practice, we have information about amplitudes (or, if you prefer, powers) on subsequent frequency bands. You know the time domain well e.g. from the oscilloscope screen, i.e. the successive values of the signal samples in time. You can compare the frequency representation of a signal to turning a knob on a radio receiver and checking the signal level at individual frequencies. You can come across an implementation of a discrete Fourier transform as DFT (discrete Fourier transform), the implementation of which is quite simple (a for loop inside the second for loop operating on input data from the sample buffer), but the computational complexity of DFT is O (N?), I.e. with increasing the amount of input data (buffer length) quickly grows the number of necessary operations (i.e. the transformation execution time). FFT (fast Fourier transform) has a more complicated implementation, but its computational complexity is less O (N * log2 (N)), which allows for faster transformation due to fewer operations required. The amount of input data for an FFT is the power of 2 (e.g. 8,16,32,64,128 etc.).
    To add the FFT library to the Arduino environment, select:
    Skic-> attach library-> manage libraries
    we search for "fft" and select arduinoFFT.
    The input signal for the transformation there will be samples from the ADC 12b in the ESP32. We will collect samples with a frequency of 40kHz and they will go to a buffer with a length of 128 samples. Sampling at 40kHz will allow the analysis of input signals up to 20kHz (Nyquist frequency). So the upper limit of the frequency of the signal that we will be able to analyze is half the sampling frequency. The voltage that we can give to the ADC is in the range 0-3.3V, at the testing stage, the signal will be fed through a 10-wire resistor. We will trigger the collection of subsequent samples from the ADC with a timer. When we collect 128 samples, we will run FFT and display the data on the display. The data in the sample buffer before FFT execution is modified by a time window function (e.g. Hanning, Hamming, etc. windows), this reduces spectral leakage and in practice it improves the quality of the data obtained. The operation of multiplying the signal by the time window can be compared to, for example, gently "increasing" the amplitude at the beginning of a piece and "fading out" at its end.
    The result of the FFT there will be two data buffers, in each of the buffers the length of usable data will be twice smaller than the length of the input buffer with samples from ADC. Successive pairs of data from buffers will be real and imaginary parts of complex numbers. Graphically, the result of the transformation can be presented as follows:
    FFT in practice using ESP32 and Arduino.
    In the zero element of the output arrays there is information about the constant component of the signal, in the subsequent elements of the array - complex numbers (gray arrows show Re, Im pairs). Complex numbers describe successive frequency bands of the tested real signal. The upper frequency of the tested signal in the example is 20kHz, we have 64 complex numbers, so the width of each band is 312.5Hz. We have 64 points that define the signal in the frequency domain, the first element refers to the frequency of 312.5Hz, the next 625Hz, etc.
    It is worth recalling here that:
    - sampling rate Fs determines the maximum frequency (Fs / 2) that we can analyze in the input signal
    - buffer length N affects the number of FFT points (N / 2), which determines the resolution with which we examine the signal in the frequency domain
    - the length of the buffer affects the number of operations needed to perform, i.e. the FFT execution time.
    Complex numbers we will present it graphically, putting the real component on the X axis and the imaginary component on the Y axis. An example complex number z = 3 + 4i will look like this:
    FFT in practice using ESP32 and Arduino.
    The module of a complex number (arrow length) carries information about the power (amplitude) at a given frequency of the analyzed signal. The modulus of the sample number "z" can be calculated from tw. Pythagoras (the root of the sum of the squares of the hypotenuses) and we get | z | = 5 (the length of the hypotenuse). The angle between the "arrow" and the X axis shows the phase of the signal and can be calculated arctg (Im / Re). Thus we have moved from the time domain to the frequency domain.
    LCD display we can handle it by adding the U8g2 library to the Arduino environment:
    Skic-> attach library-> manage libraries
    we search for ST7565 and choose U8g2.
    The used monochrome COG 128x64px graphic LCD display is based on the ST7565 controller and communicates using the SPI bus. Unfortunately, the used version of LCD-AG-C128064CF 128 * 64 ST7565R requires the connection of external 1uF capacitors, but modules with capacitors and SPI pins on the board are available. With the U8g2 library, we do not have to limit ourselves to one type of driver or interface, changing the display initialization settings, we can easily adapt the program code to another type of display https://github.com/olikraus/u8g2/wiki/u8g2setupcpp. For your LCD, the configuration looks like this:
    U8G2_ST7565_NHD_C12864_F_4W_HW_SPI u8g2 (U8G2_R0, / * cs = * / 5, / * dc = * / 4, / * reset = * / 16);
    Below is a diagram of the display outputs and the way of connecting the capacitors:
    FFT in practice using ESP32 and Arduino.
    Connection to ESP32 we can make it on a breadboard.
    Feed the tested input signal to G34 (ADC input), remembering about the allowable voltage range 0-3.3V
    The supply voltage for the LCD is taken from the 3.3V output, similarly to the GND ground.
    The boot button (G0) will toggle the program functions (time domain, FFT powers, FFT phase).
    SPI is derived from G18 (CLK), G23 (DATA), G5 (CS).
    Additionally, LCD control lines G16 (RST) and G4 (D / C).
    FFT in practice using ESP32 and Arduino.
    The whole thing when connected to the contact plates looks like this:
    FFT in practice using ESP32 and Arduino.
    The library does not work well with the selected display and the displayed image is shifted to the right (random dots visible in the vertical bar on the left). The advantage of the display is its large size, which improves readability. If you know how to eliminate the described effect, please write in this topic.
    (Offset problem solved thanks to the prompt piotr_go details below.)
    Time domain is well known to anyone who has used an oscilloscope. First, let's check if the sampling works properly and if it is possible to display the buffer contents graphically on the LCD. This is how the program works in the time domain mode in the photo and video:
    FFT in practice using ESP32 and Arduino. FFT in practice using ESP32 and Arduino.
    [movie: b358154f62] https://filmy.elektroda.pl/88_1502723869.mp4 [/ movie: b358154f62]
    For simple periodic waveforms one can estimate the frequency, phase and amplitude "by eye", for more complex signals it would be difficult. The input of the system includes signals from two generators, both signals are fed through separate 10k? resistors at the ADC input, we have the sum of the signals from both generators, a wavy sine wave is the effect of giving two sinusoidal signals of different frequencies.
    Frequency domain is a display function where we use the results of the FFT operation. The picture below shows the "fringes" on the frequencies corresponding to the frequencies of the signals fed to the ADC input. In the video you will see reducing the frequency of the signal at the output of one generator, then reducing the amplitude of the signal at the output of the other generator. In the lower right corner there is a preview of the oscilloscope screen (time domain).
    FFT in practice using ESP32 and Arduino.
    [movie: b358154f62] https://filmy.elektroda.pl/23_1502725294.mp4 [/ movie: b358154f62]
    Phase a signal at a given frequency is computable as is the amplitude as described in the section on complex numbers. It is much more popular to determine the amplitude (power) of a signal at a certain frequency. Let's try to draw a phase diagram against frequency. You have to remember that the input signal is not synchronized with the sampling (the sine wave is flowing in the time domain presentation mode). Similarly, in a phase diagram, the value of the phase will gradually change as the sine wave "flows" and the initial phase changes. The second thing is the finite accuracy of the number representation in the computer system and the fact that arctg will be calculated from the ratio of two numbers (often representing noise). Complex numbers with a small modulus value (noise, negligible data) can generate phase information similar to numbers with a large modulus value (frequencies where signal strengths are greater and data is significant). Unlike the modulus value of a complex number, the phase shifts will not show us where the signal with the greater amplitude is, so the phase diagram can resemble noise. Let us introduce the phase calculation only at the points where the modulus of the complex number will exceed the specified threshold value (e.g. 1/100 of the maximum value). Below there is a photo and a video showing a phase graph using such "masking" depending on the value of the complex number modulus, in the video you will notice a continuous change of the phase value, and a recording of the "flowing" sine in the time domain mode.
    FFT in practice using ESP32 and Arduino.
    [movie: b358154f62] https://filmy.elektroda.pl/41_1502726560.mp4 [/ movie: b358154f62]
    Connecting a different display using U8g2 is limited to changing one line in the program, and connecting the display to the appropriate SPI outputs. Let's try the OLED display with the SSD1306 driver, which was used during the tests digital UV index sensor SI1132 .
    We change the line:
    U8G2_ST7565_NHD_C12864_F_4W_HW_SPI u8g2 (U8G2_R0, / * cs = * / 5, / * dc = * / 4, / * reset = * / 16);
    on:
    U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2 (U8G2_R0, 5, 4, 16);

    And remove the line: u8g2.setContrast (255);

    We connect the display to the appropriate pins of the ESP32 module:
    FFT in practice using ESP32 and Arduino.
    The program displays the data on the new OLED display:
    FFT in practice using ESP32 and Arduino. FFT in practice using ESP32 and Arduino.
    [movie: b358154f62] https://filmy.elektroda.pl/57_1502728200.mp4 [/ movie: b358154f62]
    At the input of the system, we can easily send a signal from an electrified microphone:
    FFT in practice using ESP32 and Arduino.
    There is an "inverse" IFFT algorithm to the FFT which allows a transition from the frequency domain to the time domain.
    Below you can download the Ardino code for ESP32, remember to include the arduinoFFT and U8g2 libraries and adapting the Arduino environment to support ESP32 . The program code can be used on a board other than ESP32 after changes, including triggering sampling and ADC configuration.
    Environmental tests Arduino 1.8.3.
    What is your idea of using FFT, did you manage to make practical tests, or maybe you have extensive experience in digital signal processing and want to raise DSP-related topics?

    Cool? Ranking DIY
    Do you have a problem with Arduino? Ask question. Visit our forum Arduino.
    About Author
    TechEkspert
    Editor
    Offline 
    TechEkspert wrote 6246 posts with rating 4908, helped 16 times. Been with us since 2014 year.
  • ADVERTISEMENT
  • #2 16643233
    piotr_go
    DIY electronics designer
    TechEkspert wrote:
    The library does not work well with the selected display and the displayed image is shifted to the right (random dots visible in the vertical bar of the display on the left).

    And it could not be set?
    Or is it supposed to be like that, because it's arduino and changing one parameter in the library is black magic?
  • #3 16643348
    TechEkspert
    Editor
    Probably everything can be set, but I didn't dig into the ST7565. I assumed that the library is supposed to work just like it did with SSD1306. In the case of ST7565, maybe the initialization procedure contained in the library failed, maybe the problem was with the function preparing the buffer or sending data to the LCD, and maybe I was doing something wrong, maybe someday I will return to the LCD-AG-C128064CF 128 * 64 ST7565R and U8g2 display and maybe someone will tell you how to solve this problem.
  • ADVERTISEMENT
  • #4 16643359
    piotr_go
    DIY electronics designer
    These displays are like that, and so are oleds. One manufacturer will do X = 0 with the start address, another with X = 2.
    Please try to choose the display type or edit the library.
  • ADVERTISEMENT
  • #5 16643630
    TechEkspert
    Editor
    Oh, I understand, that is, the differences are between displays from the same group, thanks for the information.
    I checked the library and corrected this offset,
    the solution is not "portable" but if someone encounters a problem with the Arduino U8g2 library and the image shifted to the right on the LCD-AG-C128064CF 128 * 64 ST7565R then:
    enter the folder with Arduino libraries, then U8g2-> src-> clib and open the file u8x8_d_st7565.c
    Search for "NHD-C12864" or u8x8_st7565_nhd_c12864_display_info and replace:
    / * default_x_offset = * / 4,
    on
    / * default_x_offset = * / 0

    This is what I like on elektroda.pl, the material does not end after the first post.

    Below the effects (I added dots in each corner to check if nothing was lost this time).

    FFT in practice using ESP32 and Arduino.
  • #6 16683390
    WMKN2205
    Level 10  
    FFT in practice using ESP32 and Arduino.
    A very nice description. I'm already thinking how to implement it on FreeRTOS
    Unfortunately, the display (LCD-AG-C128064CF-DIW W / KK-E6) resists :( you can see artifacts.
    I used 1uF / 16V SMD capacitors. can anyone suggest something.
    Series resistor 56R with backlight, supply voltage 3.28V
  • #7 16684793
    TechEkspert
    Editor
    I have a proposal that you measure the voltages on individual LCD leads (where the capacitors are connected) and, if necessary, view the current waveforms with an oscilloscope.
    I can compare with me and maybe something can be established.
    Another idea is to programmatically try to change the contrast.

    I would love to see the implementation on RTOS, especially when experimenting with an external ADC and e.g. in a two-channel version.

    LCD / TFT are now surprisingly cheap at PLN 25-45 there is already a large selection of displays,
    the mentioned display cost ~ PLN 20 disadvantages are external capacitors, the advantage is the large size,
    while OLED costs ~ 35 PLN.
    The prices are not excessive and adding a display gives you a lot of possibilities.
  • ADVERTISEMENT
  • #8 16684893
    WMKN2205
    Level 10  
    Thanks for the quick response. I give the voltage on the next pins (I do not have the oscilloscope at the moment - it is built as you can see ;) ):
    1 -10.0V
    2 -9.02V
    3 - 7.7V
    4 - 2.4V
    5 - 0.0V ?? I'll check in a moment, maybe something has been unsoldered?
    6 - 0.0V
    7 - 1.65V
    8 - 6.77V
    9 - 4.33V
    10 -1.71V
    11 - 9.16V
    12 - 10.01V
    13 - 0.17V? -should be GND
    14.15-3.29V
    As for ADC, I was thinking more about MEMS microphones on I2S but I have not seen any sensible modules in Poland.
    If it turns out that there is something wrong with the LCD, I have plan "B" 3.2 "on ILI9340.
  • #9 16684907
    TechEkspert
    Editor
    Today I will check and let you know.
    I have an idea to continue the topic of DSP, so I invite you to comment and suggest ideas, maybe we will manage to create something interesting together.

    As for the MEMS I2S microphones, they are easy to use, but quite expensive and have limited availability, it would be worth working out MEMS PDMs are much cheaper and with better accessibility (I do not know about the parameters).

    This is how the measurements look like:
    1: 9.45V
    2: 8.40V
    3: 7.34V
    4: 2.12V
    5: 1.07V

    7: 1.60V (1.26khz 50%)
    8: 7.45V (1.26khz 50%)
    9: 4.58V (1.26khz 50%)
    10: 1.60V (1.26khz 50%)
    11: 10.30V (1.26khz 50%)
    12- 11.60V

    14.15: 3.22V
  • #10 16685332
    WMKN2205
    Level 10  
    Thanks looks similar except for "5"
    I think I messed up a bit in "8x8_d_st7565_nhd_c_init_seq []" and experimented a bit:
    static const uint8_t u8x8_d_st7565_nhd_c12864_init_seq[] = {
    
    U8X8_START_TRANSFER(), 	/* enable chip, delay is part of the transfer start */
    
    U8X8_C(0x0e2), 			/* soft reset */
    U8X8_C(0x0ae),		 /* display off */
    U8X8_C(0x040),		 /* set display start line to 0 */
    
    //U8X8_C(0x0a0),		 /* ADC set to reverse */
    //U8X8_C(0x0c8),		 /* common output mode */
    //U8X8_C(0x0a1),		 /* ADC set to reverse */
    //U8X8_C(0x0c0),		 /* common output mode */
    // Flipmode
    U8X8_C(0x0a0),		 /* ADC set to reverse */
    U8X8_C(0x0c0),		 /* common output mode */
    
    U8X8_C(0x0a6),		 /* display normal, bit val 0: LCD pixel off. */
    U8X8_C(0x0a3),		 /* LCD bias 1/9 */
    U8X8_C(0x02f),		 /* all power control circuits on */
    U8X8_CA(0x0f8, 0x000),		/* set booster ratio to 4x */
    U8X8_C(0x023),		 /* set V0 voltage resistor ratio to large*/
    U8X8_CA(0x081, 0x03f),			/* set contrast, contrast value NHD C12864, see issue 186, increased contrast to 180 (issue 219) */
    
    U8X8_C(0x0ae),		 /* display off */
    U8X8_C(0x0a5),		 /* enter powersafe: all pixel on, issue 142 */
    
    U8X8_END_TRANSFER(), 	/* disable chip */
    U8X8_END() 			/* end of sequence */
    };
    


    Added after 1 [hours] 39 [minutes]:

    I gave up a moment and I implement plan "B":
    Display for Raspberry Pi TFT 3.2 "320x240 touch panel (~ 75pln) + ESP32
    The first positive test - if I combine it with the FFT code, I'll throw it in.
  • #11 16685927
    TechEkspert
    Editor
    In the new version of the library, this code fragment looks like this:
    Code: C / C++
    Log in, to see the code


    The 3.2 "TFT display on ILI9340 with a touch interface is unfortunately a greater cost (x2) than the aforementioned monochrome displays for PLN 20-30, but the possibilities are also greater.

    Is this touch interface resistive or capacitive, does it have a controller that can send information about events (touch the panel, gesture, etc.)?
  • #12 16685948
    WMKN2205
    Level 10  
    The resistive XPT2046 controller has not yet checked what it can do, it has a touch detection output.

Topic summary

The discussion revolves around implementing Fast Fourier Transform (FFT) using the ESP32 and Arduino, focusing on practical experiments with minimal mathematical theory. Users share experiences with the ST7565 LCD display, specifically the LCD-AG-C128064CF model, addressing issues related to library configurations and display initialization. Solutions include modifying the U8g2 library to correct display offsets and troubleshooting display artifacts. Suggestions for measuring voltages and exploring MEMS microphones for audio input are also discussed, highlighting the potential for further development in digital signal processing (DSP) applications.
Summary generated by the language model.
ADVERTISEMENT