Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 8 sty 2025, o 17:14


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 11 ] 
Autor Wiadomość
PostNapisane: 31 sie 2016, o 13:06 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

Cześć,

Walczę z pewnym zagadnieniem. Otóż mam w programie tablicę:

int measure_adc[5000]; //10cio bitowych (fizycznie 16) pomiarów z przetwornika ADC.
Co przekłada się na 5s zapisu sygnału audio z częstotliwością próbkowania 10kHz.
Chciałbym przetransformować ten sygnał Dyskretną transformatą Fouriera (DTF) i zapełnić nowa tablicę (załóżmy int result[500];) Wartościami jak w analizatorze widma, ale od 1Hz do 1kHz – co 2Hz (taki zakres potrzebuję). Zdaję sobie sprawę, że dokładność będzie niższa, ale bardziej zależy mi na powtarzalności niż dokładności.

* DFT zamiast FFT ponieważ obliczenia nie będą wykonywane w czasie rzeczywistym i mam na nie sporo czasu, a algorytmy DFT wydają się prostsze. :)

Niestety nie jestem w stanie ogarnąć sam umysłem zawiłości matematycznych obliczeń DFT :(

Znalazłem taką funkcję w języku C:

https://www.nayuki.io/res/how-to-implem ... form/dft.c
ze strony: https://www.nayuki.io/page/how-to-imple ... -transform

Czy znajdzie się jakaś dobra dusza, która mnie nieco naprowadzi jak zaimplementować w/w funkcję do moich potrzeb?



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 31 sie 2016, o 14:04 
Offline
Użytkownik

Dołączył(a): 25 lip 2013
Posty: 2590
Pomógł: 128

Btw. zdajesz sobie sprawę, że będziesz potrzebował sporo RAMu (choćby na samą tablicę do przechowywania próbek)? Na pierwszą pójdzie 10k (5k * 2bajty).

Zerknij na link
Sent from my Mi-4c



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 31 sie 2016, o 14:16 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

Zdaję sobie sprawę, ale docelowo uruchamiam to w module ESP8622 gdzie już po zadeklarowaniu w/w tablic, programu głównego zostało mi jeszcze 45% pamięci



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 31 sie 2016, o 16:02 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 28 lis 2012
Posty: 283
Lokalizacja: Warszawa
Pomógł: 17

Cytuj:
Czy znajdzie się jakaś dobra dusza, która mnie nieco naprowadzi jak zaimplementować w/w funkcję do moich potrzeb?


Polecam zapoznanie się z kursem DSP na STM32 publikowanym w EdW. Akurat o DFT masz w numerze 12/2011. Tutaj możesz sobie ściągnąć z ich serwera listingi : http://elportal.pl/ftp_05/201112_borzdynski_stm_cz6.rar

_________________
Pozdrawiam
Grzegorz



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 31 sie 2016, o 16:12 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

buz11 napisał(a):
Cytuj:
Czy znajdzie się jakaś dobra dusza, która mnie nieco naprowadzi jak zaimplementować w/w funkcję do moich potrzeb?


Polecam zapoznanie się z kursem DSP na STM32 publikowanym w EdW. Akurat o DFT masz w numerze 12/2011. Tutaj możesz sobie ściągnąć z ich serwera listingi : http://elportal.pl/ftp_05/201112_borzdynski_stm_cz6.rar


Świetnie, dzięki - takiego czegoś szukałem! :)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 1 wrz 2016, o 22:05 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

No niestety nie radzę sobie :/

Funkcja do obliczenia DFT wygląda następująco:

Kod:
//wyliczanie DFT, parametry:
void dft(volatile int N, volatile double samp[], volatile double spect[], volatile double ph[]) {
  //zmienne pomocnicze
  volatile int n = 0, m = 0 ;
  volatile double real = 0.0, imagine = 0.0 ;

  for (m = 0 ; m < N ; m++) {
    real = 0.0;
    imagine = 0.0 ;

    //wylicz czesc urojona i rzeczywista
    //for(n=0 ; n<N ; n++){
    n = 0;
    while (n++ < N) {
      real    += samp[n] * cos(M_TWOPI * (double)(n * m) / (double)(N)) ;
      imagine -= samp[n] * sin(M_TWOPI * (double)(n * m) / (double)(N)) ;
    }

    //usuwanie bledow zaokraglen
    if ((int)(imagine * 100000.0) == 0) {
      imagine = 0.0;
    }
    if ((int)(real * 100000.0) == 0) {
      real = 0.0;
    }

    //wyznacz modul wartosci zespolonej
    spect[m] = sqrt(real * real + imagine * imagine) ;
    ph[m] = atan(imagine / real) / M_PI * 180.0;
  }
}


Testuję nie na całym moim buforze 5000 próbek tylko wypełniam bufor z przykładu 128 pierwszymi próbkami:

Kod:
           
for (index_res = 0 ; index_res < 128 ; index_res++) {
              samples[index_res] = measre_audio[index_res];
            }


i uruchamiam ją jak w przykładzie:

Kod:
dft(128, samples, spectrum, phase) ;


Funkcja zwraca tablicę trzech wartości:

Częstotliwość, wartość spektrum (? nie wiem czy dobrze rozumiem), i phase (jeszcze nie wiem co to :( )

W każdym razie wszystko kompiluje się i uruchamia, ale wyniki są kompletnie bezsensu i tak dla przykładu, kiedy podałem na ADC atmegi sygnał z karty dźwiękowej 500Hz uzyskuję taki wynik:

Obrazek

dla 1000Hz

Obrazek

dla 100Hz

Obrazek

Myślałem, że coś robię nie tak przy samplowaniu wiec wypełniłem tablicę próbek na sztywno wyliczeniami:

(nie wiem ile to warte, było w przykładzie)
Kod:
    //wyznacz sygnal do analizy (fs=100Hz)
    index = 0 ;
    for(time=0.0 ; time<0.1 ; time += 0.01){
        samples[index++] = 5.0 + 10.0 * sin(M_TWOPI * 20.0 * time + M_PI/4) + 15.0 * sin(M_TWOPI * 30.0 * time) ;
    }


i dostałem coś takiego:

Obrazek

Ktoś ma jakiś pomysł dlaczego?
Może analizuje za mało próbek?

I największa zagadka z tego co wyczytałem to wartość wyliczeń zależy (i pewnie słusznie) z częstotliwości próbkowania, ale skąd u licha w/w funkcja ma wiedzieć że moje sample są próbkowane 1000Hz?



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 2 wrz 2016, o 00:37 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

Doszedłem do pewnych wniosków ;)

Muszę zadeklarować:

Kod:
const int N = 10; //probek
const int fs = 1000 ; //Hz


Następnie przy wyrzucaniu wyników częstotliwość powinna być wynikiem n*(fs/N) co też było w przykładach, ale bezmyślnie skopiowałem kod z 1 części...

Wyniki są bardziej dokładne, drobne odchylenia to zapewne problemy zestawu uruchomieniowego z podłączoną płytką stykową, mnóstwem połączeń kablowych i praktycznie brakiem filtracji zasilania. Nie rozumiem natomiast dlaczego wynik jest jakby zdublowany takim lustrzanym odbiciem :/

Poniżej kilka pomiarów, im wyższa częstotliwość tym większe głupoty...

150Hz
Obrazek
300Hz
Obrazek
400Hz
Obrazek
500Hz
Obrazek
600Hz
Obrazek
900Hz
Obrazek
1000Hz
Obrazek



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 2 wrz 2016, o 09:40 
Offline
Użytkownik

Dołączył(a): 26 cze 2016
Posty: 186
Pomógł: 7

superbzyku napisał(a):
(nie wiem ile to warte, było w przykładzie)
Kod:
    //wyznacz sygnal do analizy (fs=100Hz)
    index = 0 ;
    for(time=0.0 ; time<0.1 ; time += 0.01){
        samples[index++] = 5.0 + 10.0 * sin(M_TWOPI * 20.0 * time + M_PI/4) + 15.0 * sin(M_TWOPI * 30.0 * time) ;
    }



Tu wyraźnie wyliczasz sumę 2 sinusoid masz 'sin(20*time*M_TWOPI)' i 'sin(30*time*M_TWOPI)'


Wylicz jedną u = U * sin (omega*t) = U * sin (2*Pi*f * t)
U - napięcie (amplituda), omega to pulsacja, t to czas. Iloczyn pulsacji i czasu to kąt, możesz od razu kąt zmieniać w pętli, bez zabawy w mnożenia.

W tym wypadku musi 1 prążek być, jak będzie dobrze to możesz dalej się bawić.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 2 wrz 2016, o 18:44 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

Cytuj:
W tym wypadku musi 1 prążek być, jak będzie dobrze to możesz dalej się bawić.


Zrobiłem tak:

Cytuj:

int U = 15;
int ind = 0;
for (timee=0.0 ; timee<0.1 ; timee += 0.01) {
samples[ind] = U * sin (M_TWOPI*30 * timee);
ind++;
}


I niestety są 2 prążki :(

Skąd się bierze to 70Hz :evil:

Obrazek



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 2 wrz 2016, o 23:10 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

Wykresy generuje na serwerze w php i gd2, na szybko na kolanie napisałem skrypt. Czyli powinienem brać pod uwagę tylko fazę ujemną?



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 5 wrz 2016, o 14:54 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 13 mar 2014
Posty: 40
Lokalizacja: Bielsko-Biała
Pomógł: 1

Aaaaaa o to chodzi ;)

http://zasoby.open.agh.edu.pl/~10swlaba ... /dft1.html



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 11 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Majestic-12 [Bot] i 3 gości


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO