我正在使用R并试图通过将快速傅立叶变换应用于大量声波(1000s音频文件)来恢复频率(实际上,只是接近实际频率的一个数字)每个文件并确定每个文件最高幅度的频率。我希望能够尽快恢复这些峰值频率。 FFT方法是我最近了解到的一种方法,我认为它应该适用于此任务,但我愿意接受不依赖于FFT的答案。我尝试了几种应用FFT并获得最高频率的方法,自从我的第一种方法以来,我已经看到了显着的性能提升,但是如果可能的话,我希望加快执行时间。从FFT中有效提取信号的频率
下面是示例数据:
s.rate<-44100 # sampling frequency
t <- 2 # seconds, for my situation, I've got 1000s of 1 - 5 minute files to go through
ind <- seq(s.rate*t)/s.rate # time indices for each step
# let's add two sin waves together to make the sound wave
f1 <- 600 # Hz: freq of sound wave 1
y <- 100*sin(2*pi*f1*ind) # sine wave 1
f2 <- 1500 # Hz: freq of sound wave 2
z <- 500*sin(2*pi*f2*ind+1) # sine wave 2
s <- y+z # the sound wave: my data isn't this nice, but I think this is an OK example
我试图用从seewave包fpeaks和spec函数的第一方法,并且它似乎工作。然而,这是非常缓慢的。
library(seewave)
fpeaks(spec(s, f=s.rate), nmax=1, plot=F) * 1000 # *1000 in order to recover freq in Hz
[1] 1494
# pretty close, quite slow
做多一点阅读后,我想这下方法,其中
spec(s, f=s.rate, plot=F)[which(spec(s, f=s.rate, plot=F)[,2]==max(spec(s, f=s.rate, plot=F)[,2])),1] * 1000 # again need to *1000 to get Hz
x
1494
# pretty close, definitely faster
后多一点环顾四周,我发现这种方法很好地工作。
which(Mod(fft(s)) == max(abs(Mod(fft(s))))) * s.rate/length(s)
[1] 1500
# recovered the exact frequency, and quickly!
下面是一些性能数据:
library(microbenchmark)
microbenchmark(
WHICH.MOD = which(Mod(fft(s))==max(abs(Mod(fft(s))))) * s.rate/length(s),
SPEC.WHICH = spec(s,f=s.rate,plot=F)[which(spec(s,f=s.rate,plot=F)[,2] == max(spec(s,f=s.rate,plot=F)[,2])),1] * 1000, # this is spec from the seewave package
# to recover a number around 1500, you have to multiply by 1000
FPEAKS.SPEC = fpeaks(spec(s,f=s.rate),nmax=1,plot=F)[,1] * 1000, # fpeaks is from the seewave package... again, need to multiply by 1000
times=10)
Unit: milliseconds
expr min lq median uq max neval
WHICH.MOD 10.78 10.81 11.07 11.43 12.33 10
SPEC.WHICH 64.68 65.83 66.66 67.18 78.74 10
FPEAKS.SPEC 100297.52 100648.50 101056.05 101737.56 102927.06 10
良好的解决方案将是恢复频率接近(±10赫兹)的实际频率最快的人。
更多的上下文
我有许多文件(几个GBS),各包含被调制几次第二,有时信号实际上完全消失,从而有只是沉默的基调。我想识别未调制音调的频率。我知道他们都应该在6000赫兹以下的地方,但我不知道比这更精确。如果(大,如果)我理解正确,我在这里有一个好的方法,这只是一个让它更快的问题。就我而言,我以前没有数字信号处理的经验,所以我非常感谢与数学/方法相关的任何提示和指示,以及关于如何更好地以编程方式处理这些问题的建议。
使用FFT的问题是它假定输入是周期性的。信号快照中存在的大多数频率通常不是这种情况。 –
@MatthewLundberg我的理解是我有一个音调,它是一个相对固定的频率,比如800±50Hz,有时候会进行调制,但是是信号中存在的主要频率。这将被视为是周期性的,正确的,应该通过这种方法来识别?如果没有,为什么不;我误解了什么? – Jota
我的意思是周期性的是,FFT认为给定的信号是在两个方向上背对背重复播放到无穷大。除了几个频率之外,这会引入边缘效应。这些边缘效应可能会或可能不会为您的结果着色。 –