LinkedIn YouTube Facebook
Szukaj

Newsletter

Proszę czekać.

Dziękujemy za zgłoszenie!

Wstecz
Artykuły

Obliczenie FFT na STM32 (2) – Program realizujący FFT, prezentacja wyników, wyciek widma oraz jego przyczyny

W kolejnym wpisie, dotyczącym szybkiej transformaty Fouriera, Mateusz Pluta przedstawi program służący do obliczenia FFT oraz wyniki na podstawie sygnału z generatora funkcyjnego. Zaprezentuje też, w jaki sposób częstotliwość próbkowania oraz okna wpływają na wyciek widma.

Zachęcamy do przeczytania pierwszej cześci serii: Obliczenie FFT na mikrokontrolerze STM32 (1) – Biblioteka CMSIS, wyciek widma, okna wykorzystywane do FFT, wdrożenie w projekcie

Zakres wpisu:

  • Program obliczający FFT
  • Sygnał z timera informujący o częstotliwości próbkowania
  • Wyniki FFT
  • Wyciek widma spowodowany złym doborem częstotliwości próbkowania
  • Wyciek widma spowodowany użyciem okien innych niż prostokątne, kiedy sygnał jest okresowy

Więcej artykułów na Blog IntHou


Program obliczający FFT

Funkcje uruchamiające używane peryferia: timer 2 wyzwalający konwersję oraz DMA przetwornika analogowo-cyfrowego:

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Buffer, BUFFER_SIZE);
HAL_TIM_Base_Start(&htim2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);

Inicjalizacja FFT:

arm_rfft_fast_instance_f32 fft_handler;
arm_rfft_fast_init_f32(&fft_handler, fftSize);

Funkcja obliczająca FFT: Bufor wejściowy do FFT składa się z 255 próbek, od wartości maksymalnej. Jest to przebieg wejściowy wycięty oknem prostokątnym.

Napięcie referencyjne na Discovery wynosi 3,0 V, więc wprowadzona składowa stała 1,4 V na generatorze będzie wynosiła w LSB 1911. Ta wartość jest odejmowana w linii 19. Bez usunięcia offsetu największy prążek będzie dla częstotliwości 0, czyli składowej stałej.

W poniższym kodzie używane jest okno prostokątne, dlatego zakomentowłem linie od 22 do 32. Jeśli chcesz użyć innego okna niż prostokątne, należy odkomentować wybrane okno, a zakomentować część dotyczącą okna prostokątnego.

void FFT_Calc()
  {
      if(Buffer_FFT_Status==1)
      {
          First_calculation_loop=0;
          /*Szukanie pierwszego maksimum przy którym naładowane będą kondensatory filtrujące*/
          for(uint16_t i=150; i<200; i++)
          {
              if(ADC_Buffer[i]>Max_value)
              {
                  Max_value_index=i;
                  Max_value=ADC_Buffer[i];
              }
          }

          /*Bufor zawierający 256 próbkek od wartości maksymalnej stworzony do prezentacji przebiegu wchodzącego do FFT*/
          for(uint16_t i=0; i<FFT_SAMPLES; i++)
          {
              Input_Buffer[i]= ((float32_t) (ADC_Buffer[Max_value_index+i]))-1911.0;
          }

          /*for(uint16_t i=0; i<FFT_SAMPLES; i++)
          {
                 //Blackman-Harris window
                 //Input_Buffer_Window[i]=(0.35875 - 0.48829 * cosf((2.0*PI*i) / (FFT_SAMPLES)) + 0.14128 * cosf((4.0*PI*i) / (FFT_SAMPLES)) - 0.01168 * cosf((6.0*PI*i) / (FFT_SAMPLES))) * Input_Buffer[i];

                //Hanning Window
                //Input_Buffer_Window[i]=(0.5 * (1-cosf((2.0*PI*i) / (FFT_SAMPLES)))) * Input_Buffer[i];

                //Flat top window
                //Input_Buffer_Window[i]=(0.21557895 - 0.41663158 * cosf((2*PI*i) / (FFT_SAMPLES)) + 0.277263158 * cosf((4*PI*i) / (FFT_SAMPLES)) - 0.083578947 * cosf((6*PI*i) / (FFT_SAMPLES)) + 0.006947368 * cosf((8*PI*i) / (FFT_SAMPLES))) * Input_Buffer[i];
           }*/
          
          /*Bufor używany do obliczenia FFT, został stworzony, ponieważ funkcja FFT modyfikuje bufor wejściowy*/
          for(uint16_t i=0; i<FFT_SAMPLES; i++)
          {
              
              Input_Buffer_FFT[i]=Input_Buffer[i];
            /*Input_Buffer_FFT[i]=Input_Buffer_Window[i];*/

          }

          /*Funkcja obliczająca FFT*/
          arm_rfft_fast_f32(&fft_handler,Input_Buffer_FFT,Output_Buffer_FFT, ifftFlag);

          /*Funkcja obliczająca moduł z wartości rzeczywistej i urojonej dla każdego z prążków*/
          arm_cmplx_mag_f32(Output_Buffer_FFT, Mag_Output_Buffer, fftSize/2);

          /*Funkcja szukająca wartości maksymalnej*/
          arm_max_f32(Mag_Output_Buffer, fftSize/2, &Max_Value_Mag_Buffer, &Max_Mag_Index);

          /*Wydzielenie wartości rzeczywistej i urojonej z tablicy wyników FFT*/
          for(uint16_t i=0; i<FFT_SAMPLES_HALF; i++)
          {
              real_Output_Buffer[i]=Output_Buffer_FFT[i*2];
              imag_Output_Buffer[i]=Output_Buffer_FFT[(i*2)+1];
          }

          /*Tablica przesunięcia fazowego dla każdeo prążka*/
          for(uint16_t i=0; i<FFT_SAMPLES_HALF; i++)
          {
               Angle_Output_Buffer[i]=atan2f(imag_Output_Buffer[i], real_Output_Buffer[i]);
          }

          /*Przesunięcie fazowe maksymalnego prążka*/
          Angle_Max_Output_Buffer=atan2f(imag_Output_Buffer[Max_Mag_Index],
real_Output_Buffer[Max_Mag_Index]);

          /*Informacja o zakończeniu obliczeń*/
          Calculation_finished=1;

          /*Zerowanie wartości maksymalnej*/
          Max_value=0;

      }
  }

Funkcja Callback informuje o zebraniu 512 próbek do bufora wejściowego. Zbieram dwa razy większą liczbę próbek niż potrzebuję do FFT, aby mieć pewność, że będę miał wystarczającą liczbę próbek.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        if(Calculation_finished==1 || First_calculation_loop==1)
        {
            Calculation_finished=0;
            Buffer_FFT_Status=1;
        }
    }
}

Sygnał z timera 2 informujący o częstotliwości próbkowania

Częstotliwość próbkowania została ustawiona na 80 kHz. Można to zaprogramować poprzez wyzwalanie przetwornika ADC za pomocą sygnału z timera 2:

Rys. 1. Częstotliwość timera 2

Wyniki FFT

Przebieg sygnału z generatora funkcyjnego o częstotliwości 10 kHz, na którym będzie wykonywane FFT:

Rys. 2. Przebieg sinusoidalny z generatora funkcyjnego o częstotliwości 10 kHz

Bufor wejściowy FFT to fragment przebiegu wycięty oknem prostokątnym, składający się z 256 próbek, przesunięty o składową stałą w celu wyznaczenia największej energii z częstotliwości przebiegu. Próbki zostały odczytane za pomocą programu STMStudio.

Rys. 3. Bufor 256 próbek przesunięty o składową stałą

Po wykonaniu FFT na przebiegu, odczytano 32 prążek jako prążek o największej energii:

Rys. 4. Numer prążka o największej energii

Wykorzystując okno prostokątne oraz 2n okresów, nie doświadczamy zjawiska wycieku widma, co widać na rys. 4. Podczas jednego okresu sinusoidy o częstotliwości 10 kHz zbieranych jest 8 próbek, a więc w buforze składającym się z 256 próbek będzie 32 okresy.

Rys. 5. Prążki przebiegu o częstotliwości 10 kHz z oknem prostokątnym

Wyciek widma spowodowany złym doborem częstotliwości próbkowania

Teraz przy takich samych ustawieniach częstotliwości próbkowania podałem sygnał sinusoidalny o częstotliwości 16 kHz, czyli 5 okresów. Warunek o 2n okresów nie został spełniony.

Rys. 6. Przebieg sygnału sinusoidalnego z generatora funkcyjnego o częstotliwości 16 kHz

Niespełniony warunek o liczbie 2n okresów skutkuje tym, że pojawia się wyciek widma, co można zaobserwować na rys. 7.

Rys. 7. Prążki przebiegu o częstotliwości 16 kHz i częstotliwości próbkowania 80kHz

Wyciek widma spowodowany użyciem okien innych niż prostokątne, kiedy sygnał jest okresowy

Okna są użyteczne, kiedy sygnał jest nieokresowy. Kiedy sygnał jest okresowy, najlepszym wyborem będzie okno prostokątne, co udowadniają poniższe wyniki dla różnych okien. Obliczenia FFT z wykorzystaniem okien zostały wykonane na podstawie przebiegu z rys. 2 (10 kHz), przy tej samej częstotliwości próbkowania 80 kHz.

Okno Blackmana-Harrisa:

Rys. 8. Przebieg wejściowy przemnożony przez okno Blackmana-Harrisa

Obliczone spektrum z przebiegu przemnożonego przez okno Blackmana-Harrisa:

Rys. 9. Obliczone spektrum z przebiegu 10 kHz z oknem Blackmana-Harrisa

Okno Hanninga:

Rys. 10. Przebieg wejściowy przemnożony przez okno Hanninga

Obliczone spektrum z przebiegu przemnożonego przez okno Hanninga:

Rys. 11. Obliczone spektrum z przebiegu 10 kHz z oknem Hanninga

Okno flat top:

Rys. 12. Przebieg wejściowy przemnożony przez okno Flat top

Obliczone spektrum z przebiegu przemnożonego przez okno Flat top:

Rys. 13. Obliczone spektrum z przebiegu 10 kHz z oknem Flat top

Podsumowanie

We wpisie zawarłem informację na temat programu służącego do wykonania FFT, przedstawiłem wyniki oraz omówiłem czynniki, które mają wpływ na wyciek widma.

Autor: Mateusz Pluta
Ukończył Elektrotechnikę na Politechnice Warszawskiej (Wydział Elektryczny) ze specjalnością Elektronika Przemysłowa. Interesuje się szeroko rozumianym hardware’em, a tym, co sprawia mu największą radość są szybkie interfejsy, kompatybilność elektromagnetyczna oraz przekształtniki energoelektroniczne. W swojej karierze zawodowej zajmował się automatyką i systemami gwarantowanego zasilania, a od kilku lat działa w przemyśle motoryzacyjnym. Pracował jako projektant elektroniki nad systemem bezprzewodowego ładownia aut elektrycznych, a potem w dziale zajmującym się komputerami pokładowymi do wielu marek samochodów. Obecnie skupia się na pionierskich rozwiązaniach, które będą wdrażane za kilka lat.
Współprowadzi blog o elektronice IntHou.pl