之前可能已经提出过这个问题,但我无法在任何一个地方找到我的具体答案。所以这就是:我试图找到两个USB麦克风捕获的两个音频信号(高斯白噪声)之间的时差(滞后)。没问题,我已经记录了来自两个不同流的音频,保存它们并将数据读回数组。接下来,我尝试了几种不同的方法来寻找延迟:首先采用FFT然后交叉相关,scipy.fftconvole
,零填充,并且似乎无数其他方法/策略。作为确认我计算的延迟的测试,我试图使用该时间延迟来计算声速。麦克风间距为0.6米时,我应该得到1.728毫秒的时间延迟(v = dis / time)。我将麦克风录音与源信号进行卷积,我不确定如何处理从fftconvolve
得到的峰值。从这些值我应该能够计算我的时差?你能给予的任何帮助都会很棒。
阅读数据:
samprat_1, data_1 = scipy.io.wavfile.read(sin_tone_1)
samprat_2, data_2 = scipy.io.wavfile.read(sin_tone_2)
samrat_tone_played, data_tone_played = scipy.io.wavfile.read(sin_tone_played)
卷积:
data_1 = _1_
data_2 = _2_
_tp_ = data_tone_played
convol_1_wsig = signal.fftconvolve(_1_, _tp_[::-1], "full")
convol_2_wsig = signal.fftconvolve(_2_, _tp_[::-1], "full")
此处还有FFTconvolve结果图:
答案 0 :(得分:0)
在这种情况下,最好在尝试使用真实数据之前确保算法能够处理完美数据。事实证明,即使你理解算法,Scipy也不会给出一个简单的方法来获得与相关性相对应的滞后。
所以这是我的little script:我生成两个长度不等的信号向量,但都包含一个特定信号(线性啁啾),已知延迟(分别为0.1和0.2秒)。然后我使用scipy.signal.correlate
和scipy.signal.fftconvolve
来确保我可以恢复两个信号之间的正确延迟。这可以归结为正确生成滞后矢量(即与相关索引相对应的时间矢量),并知道如何解释它们。
import numpy as np
import scipy.signal as signal
import numpy.fft as fft
try:
import pylab
except ImportError:
print("Can't import pylab, do you have matplotlib installed?")
## Generator for the ideal underlying signal
# Parameters for a linear chirp that lasts 0.5 seconds, over which the frequency
# is swept from -10 Hz to 5 Hz.
signalLength = 0.5 # seconds
fStart = -10.0 # Hz
fEnd = +5.0 # Hz
fRate = (fEnd - fStart) / signalLength
# `x` is a function that evaluates this underlying signal for any given time
# vector `t`.
x = lambda t: (np.sin(2 * np.pi * (fStart + fRate * 0.5 * t) * t) *
np.logical_and(t >= 0, t<signalLength))
## Generate some test data
fs = 100.0 # Sample rate, Hz
# First signal: lasts 2 seconds, sampled at `fs` Hz
Tend = 2.0 # seconds
t1 = np.arange(0, Tend, 1/fs)
y1 = x(t1 - 0.1)
# Plot?
try:
pylab.figure()
pylab.subplot(211)
pylab.plot(t1, y1)
except NameError:
pass
# Second signal: lasts 1 second, also sampled at `fs` Hz
t2 = np.arange(0, Tend/2, 1/fs)
y2 = x(t2 - 0.2)
try:
pylab.plot(t2, y2)
pylab.legend(['y1', 'y2'])
except NameError:
pass
## Correlate
# Evaluate the correlation
z = signal.correlate(y1, y2)
# And this is crucial: the vector of lags for which the above `z` corresponds
# to.
tz = (np.arange(z.size) - (y2.size - 1)) / fs
# Here's how to evaluate the relative delay between y1 and y2
print('y1 is y2 delayed by {} seconds'.format(tz[np.argmax(np.abs(z))]))
try:
pylab.subplot(212)
pylab.plot(tz, z)
except NameError:
pass
## Correlate with flipped y1-vs-y2 to make sure it still works
z = signal.correlate(y2, y1)
# Note that now, we subtract `y1.size` because `y1` is second argument to
# `correlate`
tz = (np.arange(z.size) - (y1.size - 1)) / fs
print('y2 is y1 delayed by {} seconds'.format(tz[np.argmax(np.abs(z))]))
try:
pylab.subplot(212)
pylab.plot(tz, z)
pylab.legend(['correlate(y1,y2)', 'correlate(y2,y1)'])
except NameError:
pass
这会产生(见图的底部):
y1 is y2 delayed by -0.1 seconds
y2 is y1 delayed by 0.1 seconds
万岁!好!因此,我们知道如果您correlate(y1, y2)
生成滞后tz
的向量,则减去y2
的长度。我们理解,在这种情况下,最大幅度相关发生在滞后,意味着“延迟y2
到y1
”的延迟。
让我们将其包装成一些用于通用重用的函数。该函数不知道采样率,因此它只返回整数滞后,但我们可以除以外的采样率。
## Wrap this in a function
def correlateWithLags(y1, y2, *args, **kwargs):
"Returns `scipy.signal.correlate` output as wel as vector of lags"
z = signal.correlate(y1, y2, *args, **kwargs)
lags = np.arange(z.size) - (y2.size - 1)
return (z, lags)
# Make sure all works as above
(z, nz) = correlateWithLags(y1, y2)
tz = nz / fs
print('y1 is y2 delayed by {} seconds: `correlateWithLags`'.format(tz[np.argmax(np.abs(z))]))
这会产生:
y1 is y2 delayed by -0.1 seconds: `correlateWithLags`
还在工作!
现在换句号,让我们用scipy.signal.correlate
替换scipy.signal.fftconvolve
。这可以大大减少长信号长度的运行时间。相关性与卷积相同,除非您必须对其中一个信号进行时间反转,但在处理完这些细节之后,结果应该完全相同,并且生成正确延迟的机制与上述相同。 / p>
## Use `fftconvolve` instead of `correlate` for fast-convolution
def fftCorrelateWithLags(y1, y2, *args, **kwargs):
"Equivalent to correlateWithLags but uses `scipy.signal.fftconvolve`"
# NOTA BENE: reverse `y2`! And if complex, need `np.conj(y2)` too!
z = signal.fftconvolve(y1, y2[::-1], *args, **kwargs)
lags = np.arange(z.size) - (y2.size - 1)
return (z, lags)
# Make sure it still works
(z, nz) = fftCorrelateWithLags(y1, y2)
tz = nz / fs
print('y1 is y2 delayed by {} seconds: `fftCorrelateWithLags`'.format(tz[np.argmax(np.abs(z))]))
仍然有效:
y1 is y2 delayed by -0.1 seconds: `fftCorrelateWithLags`
Scipy的correlate
确实应该给你一个函数,它返回对应于相关性的滞后向量。出于这个原因,我认为可以将它发布在StackOverflow上而不是http://dsp.stackexchange.com上,因为即使您理解了算法,您仍然需要处理代码废话。
后记。这是full code in a Gist。这是生成的图像,显示两个信号(顶部)和两种相关方式(correlate(y1, y2)
vs correlate(y2, y1)
,底部)。
答案 1 :(得分:0)
其他网站上的一些令人困惑的示例,经过评估 由函数cnn概括的过程。 四舍五入的功能可能等效于命令回合。
'''
Convolution , using
scipy.signals.fftconvolve.
As this routine has various options, I shall check the results
using information from various sources.
'''
import numpy as np
import scipy.signal as sg
def rounded(xv):
sv = np.sign(xv)
xv = xv*1000
xv = np.abs(xv)
xv = xv + 500
xv = xv.astype(int)
xv = xv*sv
xv = xv/1000
xv = xv.astype(int)
return xv
def cnn(vol,volf):
vol=np.transpose(vol)
volf=np.transpose(volf)
volg=sg.fftconvolve(vol,volf, mode = 'valid')
volg = rounded(volg)
#volg=np.transpose(volg)
return volg
# ------------------------------------------------------------------
# 10 10 10 0 0 0
# 10 10 10 0 0 0
# 10 10 10 0 0 0
# 10 10 10 0 0 0
# 10 10 10 0 0 0
# 10 10 10 0 0 0
# 1 0 -1
# 1 0 -1
# 1 0 -1
# 0 30 30 0
# 0 30 30 0
# 0 30 30 0
# 0 30 30 0
#
vol=[[10,10,10,10,10,10],[10,10,10,10,10,10],[10,10,10,10,10,10],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]]
vol=np.transpose(vol)
print(" ")
print(vol)
print(' ')
volf=[[-1,-1,-1],[0,0,0],[1,1,1]]
volf=np.transpose(volf)
print(volf)
print(' ')
# mode = full valid same
volg=sg.fftconvolve(vol,volf, mode = 'valid')
#volg=np.transpose(volg) # usually not required.
volg = rounded(volg)
print(volg)
# With slightly altered kernel, the result is true.
# should be
#[[0,30,30,0],[0,30,30,0],[0,30,30,0],[0,30,30,0]]
# original volf =[[-1,-1,-1],[0,0,0],[1,1,1]] , prior to adjustment or translate.
# https://www.analyticsvidhya.com/blog/2018/12/guide-convolutional-neural-network-cnn/
# From same website .
# 3 0 1 2 7 4
# 1 5 8 9 3 1
# 2 7 2 5 1 3
# 0 1 3 1 7 8
# 4 2 1 6 2 8
# 2 4 5 2 3 9
# 1 0 -1
# 1 0 -1
# 1 0 -1
# result
# -5 -4 0 8
# -10 -2 2 3
# 0 -2 -4 -7
# -3 -2 -3 -16
vol=[[3,1,2,0,4,2],[0,5,7,1,2,4],[1,8,2,3,1,5],[2,9,5,1,6,2],[7,3,1,7,2,3],[4,1,3,8,8,9]]
vol=np.transpose(vol)
print(" ....................... ")
print(" ")
print(vol)
print(' ')
volf=[[-1,-1,-1],[0,0,0],[1,1,1]]
volf=np.transpose(volf)
print(volf)
print(' ')
# mode = full valid same
volg=sg.fftconvolve(vol,volf, mode = 'valid')
volg = rounded(volg)
print(volg)
# The result is true, however the kernel is different than at the website.
# quit()
# ---------------------------------------------------------------------------
# another example , from .
# https://insightsimaging.springeropen.com/articles/10.1007/s13244-018-0639-9
# 1 2 1 0 2
# 2 0 0 1 0
# 1 0 2 1 0
# 0 1 0 2 1
# 0 2 1 0 2
# 1 0 1
# 0 1 0
# 1 0 1
# result.
# 1 4 2 0 3
# 4 5 3 6 1
# 2 2 6 2 3
# 2 5 3 7 2
# 1 2 4 1 4
vol=[[0,0,0,0,0,0,0],[0,1,2,1,0,0,0],[0,2,0,0,1,2,0],[0,1,0,2,0,1,0],[0,0,1,1,2,0,0],[0,2,0,0,1,2,0],[0,0,0,0,0,0,0]]
vol=np.transpose(vol)
print(" ")
print(vol)
print(' ')
volf=[[1,0,1],[0,1,0],[1,0,1]]
volf=np.transpose(volf)
print(volf)
print(' ')
volg = sg.fftconvolve(vol,volf, mode = 'valid')
volg = rounded(volg)
print(volg)
print(" ..........<< >>.......... ")
# Same result after applying rounded .
#quit()
# without padding .
# 1 2 1 0 2
# 2 0 0 1 0
# 1 0 2 1 0
# 0 1 0 2 1
# 0 2 1 0 2
# 1 0 1
# 0 1 0
# 1 0 1
# result
# 5 3 6
# 2 6 2
# 5 3 7
vol=[[1,2,1,0,0],[2,0,0,1,2],[1,0,2,0,1],[0,1,1,2,0],[2,0,0,1,2]]
vol=np.transpose(vol)
print(" ")
print(vol)
print(' ')
volf=[[1,0,1],[0,1,0],[1,0,1]]
volf=np.transpose(volf)
print(volf)
print(' ')
volg = sg.fftconvolve(vol,volf, mode = 'valid')
volg = rounded(volg)
print(volg)
# Same result after applying rounded .
#quit()
# ----------------------------- valid ----------------------------------
# Trying another example, from
# https://medium.com/analytics-vidhya/convolutional-neural-networks-cnn-explained-step-by-step-69137a54e5e7
# 1 1 1 0 0
# 0 1 1 1 0
# 0 0 1 1 1
# 0 0 1 1 0
# 0 1 1 0 0
# 1 0 1
# 0 1 0
# 1 0 1
# 4 3 4
# 2 4 3
# 2 3 4
vol=[[1,1,1,0,0],[0,1,1,1,0],[0,0,1,1,1],[0,0,1,1,0],[0,1,1,0,0]]
vol=np.transpose(vol)
print(" ")
print(vol)
print(' ')
volf=[[1,0,1],[0,1,0],[1,0,1]]
volf=np.transpose(volf)
print(volf)
print(' ')
volg = sg.fftconvolve(vol,volf, mode = 'valid')
volg=np.transpose(volg) # Notice syntax for this procedure .
volg = rounded(volg)
print(volg)
# This is correct, however having to take the transpose of volg is
# unexpected and differs from most of the other examples.
#quit()
# ....................................................
# Yet another example, using previous method .
# https://www.deeplearningwizard.com/deep_learning/practical_pytorch/pytorch_convolutional_neuralnetwork/
# 0 0 0 0 0 0 0
# 0 2 2 0 0 0 0
# 0 0 0 2 2 2 0
# 0 2 0 0 2 0 0
# 0 0 0 0 2 0 0
# 0 0 2 2 0 0 0
# 0 0 0 0 0 0 0
# 1 1 1
# 0 0 0
# 0 0 0
# 0 0 0 0 0
# 4 4 2 0 0
# 0 2 4 6 4
# 2 2 2 2 2
# 0 0 2 2 2
vol=[[0,0,0,0,0,0,0],[0,2,0,2,0,0,0],[0,2,0,0,0,2,0],[0,0,2,0,0,2,0],[0,0,2,2,2,0,0],[0,0,2,0,0,0,0],[0,0,0,0,0,0,0]]
vol=np.transpose(vol)
print(" ")
print(vol)
print(' ')
volf=[[0,0,1],[0,0,1],[0,0,1]]
volf=np.transpose(volf)
print(volf)
print(' ')
volg = sg.fftconvolve(vol,volf, mode = 'valid')
volg = rounded(volg)
print(volg)
# this is correct, however volf is reversed.
#quit()
# .....................................................
# https://victorzhou.com/blog/intro-to-cnns-part-1/
# 0 50 0 29
# 0 80 31 2
# 33 90 0 75
# 0 9 0 95
# -1 0 1
# -2 0 2
# -1 0 1
# 29 -192
# -35 -22
vol=[[0,0,33,0],[50,80,90,9],[0,31,0,0],[29,2,75,95]]
vol=np.transpose(vol)
print(" ...............<<<<< ")
print(vol)
print(' ')
volf=[[1,2,1],[0,0,0],[-1,-2,-1]]
volf=np.transpose(volf)
print(volf)
print(' ')
volg = sg.fftconvolve(vol,volf, mode = 'valid')
volg = rounded(volg)
print(volg.astype(int))
# this is correct, however volf is top row is reversed with bottom row.
# --------------------------------------------------------
#
# To summarize, the function cnn is mostly correct for the examples
# that I found upon the web, when one enters the data values in the
# format shown .
#