wykryć liczbę pików w nagraniu audio

12

Próbuję wymyślić, jak wykryć liczbę sylab w korpusie nagrań audio. Myślę, że dobrym proxy może być szczyty w pliku wave.

Oto, co próbowałem z plikiem mówiącym po angielsku (mój faktyczny przypadek użycia to Kiswahili). Zapis tego przykładowego nagrania brzmi: „To ja próbuję użyć funkcji timera. Patrzę na pauzy, wokalizacje”. W tym fragmencie znajduje się łącznie 22 sylab.

plik wav: https://www.dropbox.com/s/koqyfeaqge8t9iw/test.wav?dl=0

seewavePakiet w R jest wielki, i istnieje kilka możliwych funkcji. Najpierw zaimportuj plik wave.

library(seewave)
library(tuneR)
w <- readWave("YOURPATHHERE/test.wav")  
w
# Wave Object
# Number of Samples:      278528
# Duration (seconds):     6.32
# Samplingrate (Hertz):   44100
# Channels (Mono/Stereo): Stereo
# PCM (integer format):   TRUE
# Bit (8/16/24/32/64):    16

Pierwszą rzeczą, której spróbowałem, była timer()funkcja. Jedną z rzeczy, które zwraca, jest czas trwania każdej wokalizacji. Ta funkcja identyfikuje 7 wokalizacji, czyli znacznie mniej niż 22 sylaby. Szybkie spojrzenie na fabułę sugeruje, że wokalizacje nie są równe sylabom.

t <- timer(w, threshold=2, msmooth=c(400,90), dmin=0.1)
length(t$s)
# [1] 7

wprowadź opis zdjęcia tutaj

Próbowałem także funkcji fpeaks bez ustawiania progu. Zwróciło 54 szczyty.

ms <- meanspec(w)
peaks <- fpeaks(ms)

wprowadź opis zdjęcia tutaj

Wykreśla amplitudę raczej według częstotliwości niż czasu. Dodanie parametru progowego równego 0,005 odfiltrowuje szum i zmniejsza liczbę do 23 pików, co jest bardzo zbliżone do faktycznej liczby sylab (22).

wprowadź opis zdjęcia tutaj

Nie jestem pewien, czy to najlepsze podejście. Wynik będzie wrażliwy na wartość parametru progu i muszę przetworzyć dużą partię plików. Czy są jakieś lepsze pomysły na to, jak zakodować to w celu wykrycia pików reprezentujących sylaby?

Eric Green
źródło
2
To bardzo interesujące pytanie, ale możesz uzyskać lepszą pomoc dotyczącą metod w witrynie pytań i odpowiedzi na temat przetwarzania sygnałów wymiany stosów .
eipi10
ok dzięki. sprawdzi to, jeśli nikt nie odpowie. bardzo mile widziane.
Eric Green,
To tylko pomysł, ale czy warto rozważyć analizę punktu zmiany ? Analizę można łatwo przeprowadzić w R za pomocą changepointpakietu. Mówiąc najprościej, analiza punktu zmiany koncentruje się na wykrywaniu zmiany, powiązany przykład dotyczy danych handlowych, ale może być interesujące zastosowanie tej techniki do solidnych danych.
Konrad
Przyjmuję odpowiedź, która ma najwięcej głosów, co jest moją próbą wdrożenia innego pomysłu na CV. Myślę jednak, że pozostaje zasadnicze pytanie: jak korzystać z funkcji nagrań, aby dokładnie wykryć liczbę pików odpowiadającą liczbie wypowiedzianych sylab. Dziękuję za wszystkie pomysły. Wyślę tutaj, gdy będę miał rozwiązanie.
Eric Green

Odpowiedzi:

5

Nie sądzę, aby to, co następuje, było najlepszym rozwiązaniem, ale @ eipi10 miał dobrą sugestię, aby sprawdzić tę odpowiedź na CrossValidated . Więc zrobiłem.

Ogólne podejście polega na wygładzeniu danych, a następnie znalezieniu pików poprzez porównanie lokalnego filtru maksymalnego z wygładzeniem.

Pierwszym krokiem jest utworzenie argmaxfunkcji:

argmax <- function(x, y, w=1, ...) {
  require(zoo)
  n <- length(y)
  y.smooth <- loess(y ~ x, ...)$fitted
  y.max <- rollapply(zoo(y.smooth), 2*w+1, max, align="center")
  delta <- y.max - y.smooth[-c(1:w, n+1-1:w)]
  i.max <- which(delta <= 0) + w
  list(x=x[i.max], i=i.max, y.hat=y.smooth)
}

Zwracana wartość zawiera argumenty lokalnych maksimów (x) - które odpowiadają na pytanie - oraz indeksy do tablic x i y, w których występują te lokalne maksima (i).

Wprowadziłem niewielkie zmiany w testfunkcji kreślenia: (a), aby wyraźnie zdefiniować xiy oraz (b), aby pokazać liczbę pików:

test <- function(x, y, w, span) {
  peaks <- argmax(x, y, w=w, span=span)

  plot(x, y, cex=0.75, col="Gray", main=paste("w = ", w, ", span = ", 
                                              span, ", peaks = ", 
                                              length(peaks$x), sep=""))
  lines(x, peaks$y.hat,  lwd=2) #$
  y.min <- min(y)
  sapply(peaks$i, function(i) lines(c(x[i],x[i]), c(y.min, peaks$y.hat[i]),
                                    col="Red", lty=2))
  points(x[peaks$i], peaks$y.hat[peaks$i], col="Red", pch=19, cex=1.25)
}

Podobnie jak fpeakspodejście, o którym wspomniałem w moim pierwotnym pytaniu, to podejście wymaga również sporego dostrojenia. Nie będę znać odpowiedzi „właściwej” (tj. Liczby sylab / pików), więc nie jestem pewien, jak zdefiniować regułę decyzyjną.

par(mfrow=c(3,1))
test(ms[,1], ms[,2], 2, 0.01)
test(ms[,1], ms[,2], 2, 0.045)
test(ms[,1], ms[,2], 2, 0.05)

wprowadź opis zdjęcia tutaj

W tym momencie fpeakswydaje mi się trochę mniej skomplikowane, ale wciąż niezadowalające.

Eric Green
źródło
Może to być niezadowalające, ponieważ parametry lessowe nie zapewniają wystarczającego wygładzenia. Wybór bardziej płynnego musi zależeć od charakteru danych i celów; nie jest to coś, co można pozostawić cokolwiek, co oferuje platforma komputerowa i jakie wartości domyślne zapewnia.
whuber
To nie są wartości domyślne. Tylko przykłady. Zaskakuje mnie w tym przypadku większe wyzwanie związane z nauką bez nadzoru. Nie znam liczby sylab w nagraniach, więc nie jestem pewien, jak dostroić partię plików. Parametry stałe prawdopodobnie nie mają sensu, ale nie jestem pewien, jak skonfigurować inne reguły decyzyjne (np. Inne miary fali, które można by wykorzystać do ustalenia optymalnych wartości dla tych parametrów). Myślę, że muszę utworzyć zestaw szkoleniowy, który pomoże niektórym algorytmom ustawić te parametry. Nie jestem pewien.
Eric Green
W twoim poleceniu loessnie widzę wyraźnie podanych argumentów za stopniem wygładzenia. W rzeczywistości nie ma sensu biegać za ruchomym oknem: robi to już wewnętrznie.
whuber
Rozumiem co masz na myśli. Przyjąłem, że wbył to argument podczas wygładzania. Oto jak autor oryginalnego rozwiązania opisał funkcję: „Istnieją dwa parametry, które należy dostosować do okoliczności: w to połowa szerokości okna używanego do obliczenia maksimum lokalnego ... Kolejny - nie jest to jednoznaczne code - jest argumentem span mniejszej wygładzenia. "
Eric Green
Autor ten zawarł wjako jeden z parametrów, ponieważ miał na myśli bardzo ogólne podejście, w którym wygładzacz może nie być mniejszy, ale być może byłby medianą okienkową lub Hanningiem, lub czymkolwiek innym, co uznano by za odpowiednie dla statystycznego zachowania danych i cele analityka. Właściwości wielu z tych wygładzaczy zależałyby od szerokości okna.
whuber
1

Miałem podobne problemy z analizą profili elektroforezy białek. Rozwiązałem je, stosując niektóre funkcje pakietu msprocess R do drugich pochodnych profili (patrz https://fr.wikipedia.org/wiki/D%C3%A9pouillement_d 'une_courbe # Position_et_hauteur_du_pic). Zostało to opublikowane tutaj: http://onlinelibrary.wiley.com/doi/10.1111/1755-0998.12389/abstract;jsessionid=8EE0B64238728C0979FF71C576884771.f02t03

Nie mam pojęcia, czy podobne rozwiązanie może Ci pomóc. Powodzenia

user17493.bis
źródło
dzięki, @ user17493.bis. Wyrazy uznania za publikację z materiałami uzupełniającymi. znacznie ułatwi mi wypróbowanie tego pomysłu!
Eric Green,
0

Oto biblioteka w Pythonie, z której korzystałem wcześniej, próbując oszacować okresowość przez znalezienie pików w funkcji autokorelacji.

Wykorzystuje różnice / dyskretne pochodne pierwszego rzędu do wykrywania pików i obsługuje strojenie według progów i minimalnych odległości (między kolejnymi pikami). Rozdzielczość pików można również poprawić za pomocą estymacji i interpolacji Gaussa (patrz link).

Działa całkiem dobrze po wyjęciu z pudełka, bez większych poprawek, nawet w przypadku głośnych danych. Spróbuj.

tool.ish
źródło
Dzięki, @ tool.ish. Wygląda na dobrą alternatywę dla cytowanych metod R. Myślę jednak, że nadal będę miał wyzwanie strojenia.
Eric Green
0

Chciałbym zaproponować rozwiązanie wykorzystujące changepointpakiet. Poniższy uproszczony przykład próbuje zidentyfikować piki, zdefiniowane tutaj jako punkty zmiany , patrząc na jeden kanał z dostępnych danych.

Przykład

Pozyskiwanie danych

# Libs
library(seewave)
library(tuneR)

# Download
tmpWav <- tempfile(fileext = ".wav")
download.file(url = "https://www.dropbox.com/s/koqyfeaqge8t9iw/test.wav?dl=0",
              destfile = tmpWav)

# Read
w <- readWave(filename = tmpWav)

Przygotowywanie danych

# Libs
require(changepoint)

# Create time series data for one channel as an example
leftTS <- ts(data = w@left)

## Preview
plot.ts(leftTS)

Wykres wygenerowany przez plot.tspołączenie: Kanał jako szereg czasowy

Analiza punktu zmiany

changepointPakiet zawiera szereg opcji do identyfikacji zmian / piki w danych. Poniższy kod stanowi tylko prosty przykład znalezienia 3 pików przy użyciu metody BinSeg :

# BinSeg method (example)
leftTSpelt <- cpt.var(data = leftTS, method = "BinSeg", penalty = "BIC", Q = 3)
## Preview
plot(leftTSpelt, cpt.width = 3)

Uzyskany wykres: Niektóre punkty zmiany Możliwe jest również uzyskanie wartości:

cpts(leftTSpelt)
[1]  89582 165572 181053

Notatki dodatkowe

Podany przykład dotyczy głównie zilustrowania, w jaki sposób można zastosować analizę punktu zmiany do dostarczonych danych; należy zachować ostrożność w odniesieniu do parametrów przekazywanych do cp.varfunkcji. Szczegółowe wyjaśnienie pakietu i dostępnych funkcjonalności znajduje się w następującym artykule:

Killick, Rebecca i Eckley, Idris (2014) changepoint: pakiet R do analizy zmian. Journal of Statistics Software, 58 (3). s. 1-19.

ecp

ecp, jest kolejnym wartym uwagi pakietem R. ecpUłatwia przedsięwzięcie nieparametryczny wielowymiarowa analiza punkt zmiany, które mogą być przydatne, jeśli ktoś chciałby zidentyfikować punkty zmiany zachodzące w wielu kanałach.

Konrad
źródło
Dzięki, @konrad. Nie wiedziałem o żadnym pakiecie, więc dziękuję za poświęcenie czasu na demo. Myślę, że podstawowym wyzwaniem, jakie mam dla wszystkich tych pakietów, jest to, że nie wiem, ile pików ma szukać, więc nie jestem pewien, jak dostroić parametry. Nadal wydaje się to być sytuacją, w której muszę użyć jakiegoś algorytmu, aby ustalić, jak ustawić parametry, aby dokładnie zidentyfikować prawidłową liczbę pików (tj. Sylaby).
Eric Green
@EricGreen Zasadniczo analiza punktu zmiany umożliwiłaby identyfikację pików na podstawie rozkładu. Byłoby to kwestią zastosowania odpowiedniej metody, kar i tak dalej. Sugerowałbym, abyś zajrzał na stronę, do której link znajduje się w moim poprzednim komentarzu, ponieważ szczegółowo opisuje ten proces.
Konrad
Nie jestem pewien, czy dosłownie masz na myśli wyrównywanie rozkładu. Mam 2000 plików i potrzebuję sposobu na zautomatyzowanie tego. Nawet gdybym mógł zbadać każdy plik, trudno mi dostrzec liczbę sylab jako pików. Może jestem gęsty i przyjdę zobaczyć zalety tego podejścia. Nadal utknąłem na konieczności automatycznego dostrojenia parametrów każdego pliku, aby wynikowa liczba wykrytych pików była dokładnym przybliżeniem liczby sylab.
Eric Green
@EricGreen Nie, oczywiście nie literacki. Jeśli wymyślisz odpowiednie parametry, które powinny zostać przekazane do jednej z funkcji cpt , będziesz mógł uruchomić ją na dowolnej liczbie obiektów. Ponieważ nie mam specjalistycznej wiedzy z zakresu językoznawstwa, nie wiem, czy sylaby odpowiadałyby zwykłym pikom obserwowanym w danych szeregów czasowych.
Konrad
gotcha. Myślę, że natrafiam na krok „znajdź odpowiednie parametry” dla tego konkretnego przypadku użycia. Ale doceniłem wszystkie pomysły i dowiedziałem się o kilku nowych pakietach, które mogą być dobrą alternatywą dla tych, które wypróbowałem.
Eric Green