logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Wykrywanie ciszy - jaki algorytm

madzienka 18 Lut 2009 01:45 3403 14
REKLAMA
  • #1 6166506
    madzienka
    Poziom 10  
    Witam,
    chcę usunąć ciszę z końca i początku plików dźwiękowych. Piszę w c++, korzystam z biblioteki ipp. Natknęłam się w niej na funkcję wykrywająca i usuwająca ciszę, ale nie potrafię jej do końca zrozumieć. Wykorzystuje ona iloczyn skalarny wektora wejściowego i detekcję przejść przez zero. Czy zna ktos z was algorytm na wykrywanie ciszy? W jaki sposób to zrealizować itp. ? Po co ten iloczyn skalarny i przejscia przez zero?
    Z góry bardzo dziekuję.
  • REKLAMA
  • #2 6166521
    elektryk
    Poziom 42  
    Iloczyn skalarny to proste przemnożenie próbek, zapewne żeby zwiększyć amplitudę do dalszej obróbki. Daj jakiś większy kontekst, co to ma robić i jak to ma funkcjonować, bo jak dla mnie "usuwanie ciszy" brzmi dziwnie, bo jak usunąć coś czego nie ma albo jest bliskie zeru.
  • REKLAMA
  • #3 6166532
    madzienka
    Poziom 10  
    Nagrywając mowę, zawsze na początku i na końcu pliku dźwiękowego jest cisza (1-2 s, bo od momentu włączenia nagrywania do wypowiedzenia słowa mija trochę czasu), a ja chcę się jej pozbyć, żeby głos zaczynał się od początku próbki (wyciąć ten fragment z samym dźwiękiem).
  • REKLAMA
  • #4 6166748
    kevin52
    Poziom 17  
    1. Przeprowadzić detekcję obwiedni sygnału znajdując wartości maksymalne kolejnych próbek.
    2. Przyjąć wartość progową amplitudy obwiedni, dla której algorytm uzna że rozpoczyna się "sygnał właściwy". Ten proces ma odróżnić poziom tła (szumy) od początku sygnału.
    3. Przyjąć wartość progową czasu (ilości próbek) spełniających warunek amplitudy. Ten proces odfiltruje przypadkowe krótkie impulsy nie będące początkiem sygnału. Na dobrą sprawę można go również umieścić w detektorze obwiedni i uśrednieniu ciągu kolejnych "n" próbek.

    Dalsza sprawa to np. wyłączenie w/w detektora po pierwszym wykryciu aby nie ingerował np. w przerwach między słowami. Wykrycie końca sygnału w czasie rzeczywistym będzie trudniejsze, bo skąd algorytm ma wiedzieć czy to koniec sygnału, czy tylko przerwa na wzięcie oddechu ...:D Mógłby wystarczyć warunek np. > 2sek. ciszy to na pewno koniec.
    Postprocesingiem koniec można by wykryć przeprowadzając analizę od ostatniej zapisanej próbki, tzn od końca.
  • #5 6167170
    madzienka
    Poziom 10  
    Funkcja dokldnie wyglada tak:

    
    void DetectSilent(short *pInBuffer,unsigned char *pSilent,int VecSize){
       float thresholdFactor = 0.01f;
       float energyThreshold = 10000000.0f;
       float DynamicEnergyThreshold=0.0f;
       int crossnum = 45;
       int startBCnt=0,stopBCnt=0;
       short *pBuffer = pInBuffer;
       unsigned char *pSilentWork=pSilent;
       float energy = 0.0f;
       ippsDotProd_16s32f(pBuffer,pBuffer,SILDETLEN,&energy);	  //iloczyn skalarny, wynik w energy
       int crossrate;
    
       ippsSignChangeRate_16s(pBuffer,SILDETLEN,&crossrate);		//detekcja przejsc przez zero, wynik w crossrate
    
       DynamicEnergyThreshold += energy;
       float threshold = IPP_MAX(DynamicEnergyThreshold*(float)thresholdFactor, (float)crossnum);
       bool voiceFlag = false;
       if ( energy*crossrate > energyThreshold*crossnum )
           ++startBCnt;
       else
           ippsZero_8u(pSilentWork,SILDETLEN>>1);					//inicjalizacja SILDETLEN>>1 elementow wektora pSilentWork zerami
    
       pBuffer+=SILDETLEN;
       pSilentWork+=SILDETLEN;
       for(int i=SILDETLEN;i<VecSize-SILDETLEN;pSilentWork+=SILDETLEN,pBuffer+=SILDETLEN,i+=SILDETLEN){
           ippsDotProd_16s32f(pBuffer,pBuffer,SILDETLEN,&energy);	//iloczyn skalarny, wynik w energy
           DynamicEnergyThreshold += energy;
    
           ippsSignChangeRate_16s(pBuffer,SILDETLEN,&crossrate);	//detekcja przejsc przez zero, wynik w crossrate
           threshold = IPP_MAX(DynamicEnergyThreshold*(float)thresholdFactor, (float)crossnum);
           if (!voiceFlag){
               if ( energy*crossrate > energyThreshold*crossnum ||  crossrate >= crossnum){
                   if (++startBCnt >= STARTBLOCK) {
                       voiceFlag = true;
                       stopBCnt = 0;
                   }
               }
               else{
                   if (startBCnt<=1)
                       ippsZero_8u(pSilentWork-(SILDETLEN>>1),SILDETLEN);
                   else
                       ippsZero_8u(pSilentWork-SILDETLEN*(startBCnt)-(SILDETLEN>>1),SILDETLEN*startBCnt);
                   startBCnt = 0;
               }
           }
           else if ( energy*crossrate < threshold*crossnum*2 || crossrate >= crossnum*2 || energy < threshold*2){
               if (++stopBCnt >= STOPBLOCK){
                   startBCnt=0;
                   voiceFlag=false;
                   DynamicEnergyThreshold=0.0f;
               }
           }
           else stopBCnt = 0;
       }
    
    }
    


    Po tym co napisales rozumiem, że ten iloczyn skalarny wykonywany na 160 elemetach tablicy (bo SILDETLEN = 160) oblicza właśnie te wartości maksymalne dla kolejnych próbek (każda próbla po 160 elementów).

    Zastanawiams ie co to za zmienne
    
     float thresholdFactor = 0.01f;
       float energyThreshold = 10000000.0f;
       float DynamicEnergyThreshold=0.0f; 
    
  • Pomocny post
    #6 6168332
    kevin52
    Poziom 17  
    Nie jestem biegły w C... ale z tego co widzę, ten Twój algorytm jest mądrzejszy od mojego (trochę teoretycznego) o to, że próg decyzyjny cisza/niecisza jest ustalany nie w odniesieniu do bezwzględnego zera, ale dynamicznie, w odniesieniu do obliczonego wcześniej poziomu tła, czyli niejako jest bardziej adaptacyjny do sygnału rzeczywistego. Po to wprowadzili tyle współczynników progowych. Ciekawe jest to obliczanie "energy". Wygląda że po prostu mnoży próbki przez siebie. Jeszcze miałem spytać, skąd wyszło że SILDETLEN, liczy akurat 160 sampli? :D
  • #7 6168578
    madzienka
    Poziom 10  
    Mam przykład w którym wykorzystywana jest ta funkcja i w nim sildenlen wynosi 160. Nie wiem dlaczego. Może ty wiesz na jakiej podstawie liczy sie ta zmienna?
    Jeszcze miałam zapytac co to jest crossrate i po co ta detekcja przejsc przez zero iczemu crossnum (i co to) równe 45?
    Dodam ze wektor pSilence jest przed wywolaniem DetectSilent wypełniany jedynkami i jest długosci wektora pInBuffer(z danymi).
    Z tego co wywnioskowałam pSilent wypelniany jest zerami w tych miejscach gdzie w pInBuffer jest cisza. Dobrze myslę?

    Mówisz, ze neie jestes biegly w c, to moze napisz mi czego nie rozumiesz to przetlumacze :)
  • Pomocny post
    #8 6171679
    kevin52
    Poziom 17  
    Witam ponownie,
    ramka (blok) 160 "samplowa" wzięła się z jednego z codeków GSM, a konkretnie z GSM 06.60 Enhanced Full Rate Encoder. Przy częstotliwości próbkowania mowy 8kHz, ramka 160 sampli to dokładnie 20ms. Taka ramka wystarcza do kompletnej analizy mowy i wyodrębnienia wszystkich współczynników koniecznych do kompresji. Wykrywanie cisza/mowa jest jednym z podprocesów kompresji mowy do celów transmisji gsm.
    Jeśli chodzi o detekcję cisza/mowa, którą widać powyżej jest to algorytm wymyślony i nawet opatentowany, zawarty w rekomendacji ITU G.729 Annex B. Chciałem go nawet ściągnąć ale jest płatny... Być może dłużej poszukać gdzieś by się znalazło. Jest tylko krótki opis tego algorytmu, ale tekst jest dość trudny, musiałbym się bardziej wgryść w tematykę. Z grubsza polega to na analizie ilości przejść przez zero w bloku 160 sampli i liczeniu poziomu ich energii, a to łatwo rozróżnia typ ciągu próbek: szum to maksymalna ilość przejść, ale mała energia; mowa-mała ilość przejść, i duża energia. Banda współczynników określa wartości progowe algorytmu. Reszta procedury to dyskryminacja tej informacji i obsługa buforów.
    Tu jest link do tej rekomendacji Link
    Nie zauważyłem plusika..:| DynamicEnergyThreshold += energy; Ta zmienna kumuluje wartość energii ciągu próbek.
    Ten bufor 0/1 stanu ciszy/mowy może być wykorzystywany do sterowania współczynnikiem kompresji.
  • #9 6171762
    madzienka
    Poziom 10  
    A co to jest ta energia tych próbek, o czym ona informuje? i po co te flagi int startBCnt=0,stopBCnt=0?
    Przepraszam, że tak pytam, ale chciałabym to zrozumieć, a widzę, że się na tym znasz :)
  • REKLAMA
  • #10 6172261
    kevin52
    Poziom 17  
    madzienka napisał:
    Przepraszam, że tak pytam...

    Przeprosiny przyjęte, nie gniewam się :D
    Odnośnie energii:
    ippsDotProd_16s32f(pBuffer,pBuffer,SILDETLEN,&energy);
    DynamicEnergyThreshold += energy;

    Funkcja mnoży próbki przez siebie, jest to zapewne detekcja amplitudy. Potem wektory są sumowane, w wyniku otrzymamy ich sumaryczną wartość , co można potraktować jako energię danego bloku. To wskazuje zmienna DynamicEnergyThreshold. Nie rozumiem dokładnego działania tej całej funkcji, więc nie powiem czy to dotyczy wszystkich naszych magicznych 160 sampli, czy tylko fragmentu bufora, więc potraktuj moje wyjaśnienia z dystansem...
    Odnośnie flag startBCnt=0,stopBCnt=0, to nie będę fantazjował, do końca nie wiem :cry:, tak jak nie wiem co to STARTBLOCK i STOPTBLOCK - to są zmienne? funkcje? jakieś operatory? Może to są "podbloki" zdetektowanej małej/dużej energii w ramach całego bloku. Jak wspominałem C++ to jak tak średnio...
    Czy ta cała funkcja DetectSilent nie została wyjęta z większej całości?
  • #11 6172521
    madzienka
    Poziom 10  
    SILDETLEN = 160
    STARTBLOCK = 4
    STOPBLOCK = 35

    Dodano po 4 [godziny] 50 [minuty]:

    
    if ( energy*crossrate > energyThreshold*crossnum ||  crossrate >= crossnum){
                   if (++startBCnt >= STARTBLOCK) {
                       voiceFlag = true;
                       stopBCnt = 0;
                   }
               } 
    


    z tego wynika, że jeżeli energia pomnożona z ilością przejść przez zero jest większa od iloczynu wartości progowych lub ilość przejść przez zero jest większa od wartości progowej to mamy do czynienia z głosem (pomijam ten następny warunek, bo nie wiem o co chodzi, ale po nim voiceflag = true)
    Dziwi mnie ten warunek
    
    crossrate >= crossnum
    

    bo zgodnie z tym co powiedziałeś mała ilość przejść przez zero oznacza szum tla, atu jest ustawiana flaga voiceFlag...

    Dodano po 2 [minuty]:

    Pozatym w momencie gdy flaga głosu jest ustawiona sprawdzany ejst warunek:
    
    if ( energy*crossrate < threshold*crossnum*2 || crossrate >= crossnum*2 || energy < threshold*2)
    


    Dlaczego akurat ten i dlaczego niektore wartosci progowe mnozone sa przez dwa ?


    || - oznacza lub w warunku

    Dodano po 52 [minuty]:

    Nadal nie rozumiem co to jest energia sygnału? Tzn rozumiem, że to są wymnożone próbki i dodane do siebie (iloczyn skalarny), ale tak prostymi słowami co nam to daje? Informuje nas jak dużą informację niesie dana podpróbka (160 sampli) ?
  • #12 6175172
    kevin52
    Poziom 17  
    Może najpierw wyprostujmy:
    madzienka napisał:

    bo zgodnie z tym co powiedziałeś mała ilość przejść przez zero oznacza szum tla, atu jest ustawiana flaga voiceFlag...

    Tak nie powiedziałem, przeczytaj jeszcze raz wyżej. A tu mały dowód: dwa sygnały Fs=8kHz, czas 50ms (czyli 2,5 naszego bufora, bo wyraźniej widać):
    zgłoska AAAAAA (moja) oraz szum biały. Porównaj sobie ilość przejść przez zero...

    Wykrywanie ciszy - jaki algorytm

    Wykrywanie ciszy - jaki algorytm

    Wracając do energii... W tym algorytmie to pojęcie umowne. W duużym uproszczeniu można stwierdzić, że słowa są GŁOŚNE (duża energia dźwięku), a szum cichy i to je odróżnia.

    Te procedury decyzyjne, które wypisałaś powyżej przeanalizuję trochę później... Są bardzo ciekawe bo w nich jest całe sedno tego algorytmu!
    Przepraszam nie dysponuję za dużą ilością czasu... :|
  • #13 6187233
    tgatga
    Poziom 1  
    Ten algorytm z IPP powinien zadziałać. Trzeba dokładnie przeczytać w dokumentacji co oznaczają poszczególne parametry i nie zmieniając ich przetestować kilka próbek różnie nagranych próbek aż natrafimy na takie gdzie będzie działał. Potem można poeksperymentować z właściwym doborem parametrów.
    Aby całość się udała należy przygotować odpowiednią procedurę testową i wiedzieć jak na podstawie danych zwracanych przez odpowiednie funkcje IPP wygenerować próbkę bez ciszy co znajduje się w dokumentacji.
  • #14 6201696
    kevin52
    Poziom 17  
    Witam,
    trochę to gryzłem i poczytałem te zalecenia i patenty ITU. Kurna... skomplikowane to trochę...
    Doczytałem, że w procesie detekcji ciszy znajdywanie i uśrednianie progów szumów, minimalnej i maxymalnej energii mowy odbywa się w dłuższym czasie, konkretnie pisali tam o 1,28sek. To jest logiczne, bo trudno na podstawie próbki 20ms ustalić jakieś średnie poziomy, to musi trwać dłużej.
    Być może ten fragment z pętlami iteracyjnymi tego właśnie dotyczy.
    A w ogóle mam pytanie? Czy Tobie zależy na ogólnym zarysie procesu detekcji, czy musisz "rozkminić" wiersz po wierszu tej funkcji?
  • #15 6263155
    slow17
    Poziom 11  
    Witam!

    Właśnie zabieram się za pisanie pracy magisterskiej i mi też będzie potrzebny dobry algorytm do wykrywania ciszy. U siebie będę musiał separować wypowiadane słowa. Narazie napisałem sobie jakiś prymitywny algorytm. Jednak ten z ITU wygląda ciekawiej. Gdyby ktoś miał jakieś materiały w wersji elektronicznej na ten temat to ja bym sobie chętnie na nie looknął. Pozdrawiam
REKLAMA