检测音频记录中的峰值数量


12

我正在尝试弄清楚如何检测一个录音语料库中的音节数。我认为一个好的代理可能是wave文件中的峰值。

这是我尝试用英语说的文件的内容(我的实际用例是斯瓦西里语)。该示例录音的记录是:“这是我试图使用计时器功能。我正在查看暂停和发声。” 此段落共有22个音节。

WAV文件:https//www.dropbox.com/s/koqyfeaqge8t9iw/test.wav? dl = 0

seewaveR中的程序包很棒,并且有多个潜在功能。首先,导入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

我尝试的第一件事是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
这是一个非常有趣的问题,但是您可能会在Stack Exchange Signal Processing Q&A站点上获得有关方法的更好帮助。
eipi10 '16

好,谢谢。如果没有人回应,它将进行检查。非常感激。
埃里克·格林

只是一个想法,但是考虑进行变更点分析是否值得?使用该软件包,可以在R中轻松进行分析changepoint。简而言之,变化点分析着重于检测变化,链接的示例涉及贸易数据,但是将这种技术应用于声音数据可能会很有趣。
Konrad,2016年

我将接受投票最多的答案,而这恰恰是我尝试实施另一个简历创意的尝试。但是,我认为核心问题仍然是:如何使用录音的功能来准确检测与所讲的音节数量相对应的多个峰值。感谢您的所有想法。如果有解决办法,我会在这里寄回。
埃里克·格林

Answers:


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绘图函数进行了少量修改:(a)显式定义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

这些不是默认值。只是例子。在这种情况下,我对无监督学习的更大挑战感到困惑。我不知道录音中的音节数,所以我不确定如何调整一批文件。常量参数可能没有意义,但是我不确定如何设置其他决策规则(例如,可以用于确定这些参数的最佳值的wave的其他指标)。我在想我需要创建一个训练集,以帮助一些算法设置这些参数。虽然不确定。
Eric Green

在您对的命令中loess,我没有看到为平滑度明确指定的参数。实际上,在移动的窗口上运行黄土没有什么意义:它已经在内部完成了。
whuber

我明白你的意思。我认为这w是平滑的一个论据。这是最初的解决方案的作者是如何描述的功能:“有两个参数进行调整的情况:w是窗口的半宽度来计算局部最大...另一个-在这种不明确代码-是黄土平滑度的跨度参数。”
Eric Green

该作者将其w作为参数之一,是因为他想到了一种非常通用的方法,在这种方法中,平滑器可能不是黄土,而是窗口中位数或Hanning或任何其他适合于数据和数据统计行为的东西。分析人员的目标。许多平滑器的属性将取决于窗口的宽度。
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/abstract;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软件包提供了许多选项来标识数据中的变化/峰值。下面的代码仅提供一个使用BinSeg方法查找3个峰的简单示例:

# 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和Eckley,Idris(2014)变更点:用于变更点分析的R包。统计软件杂志,58(3)。1-19页。

ecp

ecp,是另一个值得一提的R包。这ecp有助于进行非参数多变量更改点分析,如果希望识别跨多个通道发生的更改点,这可能会很有用。


谢谢,@ konrad。我对这两个软件包都不了解,因此感谢您抽出宝贵的时间进行演示。我认为所有这些软件包的基本挑战在于,我不知道要寻找多少个峰,因此我不确定如何调整参数。这似乎仍然是一种情况,我必须使用某种算法来确定如何设置参数以准确识别正确的峰数(即音节)。
Eric Green

@EricGreen在原则上,通过更改点分析,您可以仅通过查看分布来识别峰。应用适当的方法,处罚等问题。我建议您看看我以前的评论中链接的网站,因为它详细概述了该过程。
Konrad

我不确定您的字面意思是否会引起关注。我有2000个文件,需要一种自动化的方法。即使我可以检查每个文件,也很难将音节的数量看成是峰值。也许我很忙,我会来看这种方法的优点。我仍然坚持需要一种自动调整每个文件的参数的方法,因此所检测到的峰值数量可以准确地代表音节数量。
埃里克·格林

@EricGreen不,当然不是文学。如果您确定应该传递给cpt函数之一的适当参数,则可以在任意数量的对象上运行它。由于我没有语言学方面的专业知识,所以我不知道音节是否与时间序列数据上观察到的通常峰值相对应。
Konrad

知道了。我认为我正在为此特定用例准备“确定适当的参数”步骤。但是我很欣赏所有这些想法,并了解了一些新的软件包,这些软件包可以替代我尝试的软件包。
Eric Green
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.