виявити кількість піків аудіозапису


12

Я намагаюся розібратися, як виявити кількість складів у корпусі аудіозаписів. Я думаю, що хороший проксі може бути піками у файлі хвиль.

Ось що я спробував із файлом про мене, що розмовляв англійською мовою (мій фактичний випадок використання - у Kiswahili). Стенограма цього прикладу запису: "Це я намагаюся використовувати функцію таймера. Я дивлюся на паузи, вокалізації". В цьому уривку є всього 22 склади.

WAV файл: https://www.dropbox.com/s/koqyfeaqge8t9iw/test.wav?dl=0

seewaveПакет в R великий, і є кілька потенційних функцій. Спочатку спочатку імпортуйте файл хвилі.

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

Перше, що я спробував - це timer()функція. Одна з речей, яку вона повертає, - тривалість кожної вокалізації. Ця функція ідентифікує 7 вокалізацій, що далеко не 22 складів. Швидкий огляд сюжету говорить про те, що вокалізація не дорівнює складам.

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

введіть тут опис зображення

Я також спробував функцію fpeaks, не встановлюючи поріг. Він повернув 54 вершини.

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

введіть тут опис зображення

Це графіки амплітуди за частотою, а не за часом. Додавання порогового параметра, що дорівнює 0,005, відфільтровує шум і зменшує кількість до 23 піків, що досить близько до фактичної кількості складів (22).

введіть тут опис зображення

Я не впевнений, що це найкращий підхід. Результат буде чутливим до значення порогового параметра, і я повинен обробити велику партію файлів. Будь-які кращі ідеї щодо того, як кодувати це для виявлення піків, які представляють склади?


2
Це дуже цікаве запитання, але ви можете отримати кращу допомогу щодо методів на веб-сайті Q&A з обробки сигналів стека .
eipi10

добре, дякую. перевірить це, якщо ніхто не відповість. цінується.
Ерік Грін

Просто ідея, але чи варто було б розглянути питання про проведення аналізу змін ? Аналіз можна легко здійснити в R за допомогою changepointпакета. Простіше кажучи, аналіз точки зміни зосереджується на виявленні змін, пов'язаний приклад стосується торгових даних, але це може бути цікаво застосувати цю техніку до надійних даних.
Конрад

Я прийму відповідь, яка має найбільше голосів, і це моя спроба реалізувати іншу резюме. Я думаю, що головне питання залишається, однак: як використовувати функції записів, щоб точно виявити кількість піків, що відповідає кількості вимовлених складів. Дякую за всі ідеї. Я опублікую тут, коли знайду рішення.
Ерік Грін

Відповіді:


5

Я не думаю, що наступне - найкраще рішення, але @ eipi10 мав гарну пропозицію перевірити цю відповідь на CrossValidated . Так я і зробив.

Загальний підхід полягає в згладжуванні даних, а потім пошуку піків шляхом порівняння локального максимального фільтра з гладким.

Першим кроком є ​​створення argmaxфункції:

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)
}

Його повернене значення включає аргументи локальних максимумів (x) - це відповідає на питання - та індексує у масиви x- та y, де виникають ці локальні максимуми (i).

Я вніс незначні зміни в testграфічну функцію: (а) чітко визначити x і y і (b) показати кількість піків:

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)
}

Як і fpeaksпідхід, про який я згадував у своєму первісному запитанні, цей підхід також потребує гарної настройки. Я не знаю "правильної" відповіді (тобто кількості складів / піків), що входить до цього, тому я не знаю, як визначити правило рішення.

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)

введіть тут опис зображення

На даний момент fpeaksмені здається трохи менш складним, але все ще не задовольняє.


Це може бути незадовільним, оскільки ваші лесові параметри недостатньо згладжують. Вибір більш гладкого повинен орієнтуватися на характер даних та цілі; це не те, що можна залишити тому, що пропонується обчислювальною платформою та типовими значеннями, які вона надає.
whuber

Це не за замовчуванням. Просто приклади. Мене спантеличує більший виклик непідконтрольного навчання в цьому випадку. Я не знаю кількості складів у записах, тому я не впевнений, як налаштувати пакет файлів. Постійні параметри, ймовірно, не мають сенсу, але я не впевнений, як встановити деякі інші правила рішення (наприклад, інші показники хвилі, які можна було б використовувати для визначення оптимальних значень для цих параметрів). Я думаю, що мені потрібно створити навчальний набір, який допомагає деякому алгоритму встановити ці параметри. Не впевнений, хоча.
Ерік Грін

У вашій команді до loess, я не бачу аргументів, явно наведених для ступеня вирівнювання. Власне, лессі над рухомим вікном мало сенсу: це вже робиться всередині.
whuber

Я бачу вашу думку. Я припускав, що wце був аргумент у згладжуванні. Ось як автор оригінального рішення описав функцію: "Є два параметри, які слід налаштовувати на обставини: w - половина ширини вікна, що використовується для обчислення локального максимуму ... Інший - не явний в цьому код - це аргумент "span" плавнішого ".
Ерік Грін

Цей автор включив wяк один із параметрів, тому що мав на увазі дуже загальний підхід, при якому більш плавне може бути не лессовим, але, можливо, це буде посередньою вікном або Ханнінгом, або будь-що інше, що вважається відповідним для статистичної поведінки даних і цілі аналітика. Властивості багатьох цих плавніше залежали б від ширини вікна.
whuber

1

У мене були подібні проблеми з аналізом профілів електрофорезу білків. Я вирішив їх, застосувавши деякі функції пакету msprocess R на другому похідному профілі (див. Https://fr.wikipedia.org/wiki/D%C3%A9pouillement_d 'une_courbe # Position_et_hauteur_du_pic). Це було опубліковано тут: http://onlinelibrary.wiley.com/doi/10.1111/1755-0998.12389/abrief;jsessionid=8EE0B64238728C0979FF71C576884771.f02t03

Я не маю уявлення, чи може подібне рішення працювати у вас. Удачі


спасибі, @ user17493.bis. кудо вам за публікацію з додатковими матеріалами. мені так буде простіше спробувати цю ідею!
Ерік Грін,

0

Ось бібліотека в Python, яку я використовував раніше, намагаючись оцінити періодичність, знаходячи піки функції автокореляції.

Він використовує відмінності / дискретні похідні першого порядку для виявлення піків та підтримує настройку за параметрами порогових та мінімальних відстаней (між послідовними піками). Можна також підвищити пікову роздільну здатність, використовуючи оцінку щільності та інтерполяцію Гаусса (див. Посилання).

Для мене це спрацювало непогано, без особливих налаштувань, навіть для галасливих даних. Спробувати.


Дякую, @ tool.ish. Це виглядає як хороша альтернатива методам R, які я цитував. Я думаю, що все-таки у мене буде проблема з налаштуванням.
Ерік Грін

0

Я хотів би запропонувати рішення, використовуючи changepointпакет. Наведений нижче приклад спроби ідентифікувати піки, визначені тут як точки зміни , переглядаючи один канал із доступних даних.

Приклад

Збір даних

# 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)

Підготовка даних

# Libs
require(changepoint)

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

## Preview
plot.ts(leftTS)

Діаграма, згенерована під час plot.tsвиклику Канал як часовий ряд

Аналіз змін змін

changepointПакет надає ряд опції для ідентифікації зміни / піків в даних. Нижче наведений простий приклад пошуку 3 піків методом BinSeg :

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

Отримана діаграма: Деякі зміни Також можна отримати значення:

cpts(leftTSpelt)
[1]  89582 165572 181053

Бічні нотатки

Наведений приклад здебільшого стосується ілюстрації, як аналіз точки зміни може бути застосований до наданих даних; слід дотримуватися обережності щодо параметрів, переданих cp.varфункції. Детальне пояснення пакета та наявних функцій наведено в наступному документі:

Killick, Rebecca and Eckley, Idris (2014), точка зміни: R-пакет для аналізу точок зміни. Журнал статистичного програмного забезпечення, 58 (3). С. 1-19.

ecp

ecp, є ще одним варто згадати R пакет. Це ecpсприяє проведенню непараметричного багатоваріантного аналізу точок зміни, який може бути корисним, якщо хотілося б визначити точки зміни, що відбуваються через декілька каналів.


Дякую, @konrad Я не знав ні про один пакет, тому дякую, що знайшли час на демонстрацію. Я думаю, що основний виклик, який я маю перед усіма цими пакунками, полягає в тому, що я не знаю, скільки піків шукати, тому я не впевнений, як налаштувати параметри. Це все ще здається ситуацією, коли мені потрібно використовувати якийсь алгоритм, щоб визначити, як встановити параметри, щоб точно визначити правильну кількість піків (тобто складів).
Ерік Грін

@EricGreen В основному аналіз точки зміни дозволить вам визначити свої піки, просто переглянувши розподіл. Було б питання про застосування відповідного методу, штрафних санкцій тощо. Я б запропонував вам ознайомитись із веб-сайтом, пов’язаним у моєму попередньому коментарі, оскільки він детально окреслює процес.
Конрад

Я не впевнений, чи ви буквально маєте на увазі вирівнювання очей розподілом. У мене є 2000 файлів і мені потрібен спосіб автоматизувати це. Навіть якщо я міг би вивчити кожен файл, мені важко бачити кількість складів як піки. Можливо, я щільний, і я побачу достоїнства такого підходу. Я все ще застряг у необхідності способу автоматичної настройки параметрів кожного файлу, щоб отримана кількість піків виявила точний проксі для кількості складів.
Ерік Грін

@EricGreen Ні, не літературно, звичайно. Якщо ви визначитеся з відповідними параметрами, які слід передати одній із функцій cpt, ви зможете запускати його через будь-яку кількість об'єктів. Оскільки я не знаю лінгвістики, я не знаю, чи відповідатимуть склади звичайним пікам, що спостерігаються за даними часових рядів.
Конрад

gotcha. Я думаю, що я натрапляю на крок "з'ясувати відповідні параметри" для цього конкретного випадку використання. Але я оцінив усі ідеї та дізнався про кілька нових пакунків, які можуть стати гарною альтернативою тим, що я спробував.
Ерік Грін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.