找出两个(非谐波)波之间的相位差。

17

我有两个数据集,列出了两个神经网络组件在时间t时的平均电压输出,看起来像这样:

A = [-80.0, -80.0, -80.0, -80.0, -80.0, -80.0, -79.58, -79.55, -79.08, -78.95, -78.77, -78.45,-77.75, -77.18, -77.08, -77.18, -77.16, -76.6, -76.34, -76.35]

B = [-80.0, -80.0, -80.0, -80.0, -80.0, -80.0, -78.74, -78.65, -78.08, -77.75, -77.31, -76.55, -75.55, -75.18, -75.34, -75.32, -75.43, -74.94, -74.7, -74.68]

当两个神经元集合在相当程度上“同步”时,这意味着它们是相互关联的。我想要做的是计算A和B之间的相位差异,最好是整个模拟时间内的差异。由于两个神经元集合不太可能完全同步,因此我想将相位差异与某个阈值进行比较。
这些是不谐振子,我不知道它们的功能,只知道这些值,所以我不知道如何确定相位或相应的相位差。
我正在使用numpy和scipy(两个神经元集合都是numpy数组)在Python中进行此项目。
任何建议都将不胜感激!
编辑:添加图表 示例组件1的数据文件 示例组件2的数据文件 以下是两个数据集的图表: 重叠的两个神经元集合图 分离的两个神经元集合图

请检查您的数据文件。它们充满了“80年代”的东西! - Dr. belisarius
2个回答

38
也许您正在寻找交叉相关性:
scipy.​signal.​signaltools.correlate(A, B)

交叉相关中峰值的位置将是相位差的估计。

编辑 3: 现在我已经查看了真实数据文件,有两个原因导致您发现相移为零。首先,您的两个时间序列之间的相移确实为零。如果您在 matplotlib 图形上水平缩放,就可以清楚地看到这一点。其次,首先对数据进行规范化(最重要的是减去平均值),否则数组末端的零填充效果会淹没交叉相关中的真实信号。在下面的示例中,我验证了我找到“真实”峰值的方法,通过添加人工位移,然后检查是否正确恢复。

import numpy, scipy
from scipy.signal import correlate

# Load datasets, taking mean of 100 values in each table row
A = numpy.loadtxt("vb-sync-XReport.txt")[:,1:].mean(axis=1)
B = numpy.loadtxt("vb-sync-YReport.txt")[:,1:].mean(axis=1)

nsamples = A.size

# regularize datasets by subtracting mean and dividing by s.d.
A -= A.mean(); A /= A.std()
B -= B.mean(); B /= B.std()

# Put in an artificial time shift between the two datasets
time_shift = 20
A = numpy.roll(A, time_shift)

# Find cross-correlation
xcorr = correlate(A, B)

# delta time array to match xcorr
dt = numpy.arange(1-nsamples, nsamples)

recovered_time_shift = dt[xcorr.argmax()]

print "Added time shift: %d" % (time_shift)
print "Recovered time shift: %d" % (recovered_time_shift)

# SAMPLE OUTPUT:
# Added time shift: 20
# Recovered time shift: 20

编辑:以下是使用虚假数据演示其工作原理的示例。

编辑2:添加了一个示例的图表。

嘈杂的非谐波信号的交叉相关

import numpy, scipy
from scipy.signal import square, sawtooth, correlate
from numpy import pi, random

period = 1.0                            # period of oscillations (seconds)
tmax = 10.0                             # length of time series (seconds)
nsamples = 1000
noise_amplitude = 0.6

phase_shift = 0.6*pi                   # in radians

# construct time array
t = numpy.linspace(0.0, tmax, nsamples, endpoint=False)

# Signal A is a square wave (plus some noise)
A = square(2.0*pi*t/period) + noise_amplitude*random.normal(size=(nsamples,))

# Signal B is a phase-shifted saw wave with the same period
B = -sawtooth(phase_shift + 2.0*pi*t/period) + noise_amplitude*random.normal(size=(nsamples,))

# calculate cross correlation of the two signals
xcorr = correlate(A, B)

# The peak of the cross-correlation gives the shift between the two signals
# The xcorr array goes from -nsamples to nsamples
dt = numpy.linspace(-t[-1], t[-1], 2*nsamples-1)
recovered_time_shift = dt[xcorr.argmax()]

# force the phase shift to be in [-pi:pi]
recovered_phase_shift = 2*pi*(((0.5 + recovered_time_shift/period) % 1.0) - 0.5)

relative_error = (recovered_phase_shift - phase_shift)/(2*pi)

print "Original phase shift: %.2f pi" % (phase_shift/pi)
print "Recovered phase shift: %.2f pi" % (recovered_phase_shift/pi)
print "Relative error: %.4f" % (relative_error)

# OUTPUT:
# Original phase shift: 0.25 pi
# Recovered phase shift: 0.24 pi
# Relative error: -0.0050

# Now graph the signals and the cross-correlation

from pyx import canvas, graph, text, color, style, trafo, unit
from pyx.graph import axis, key

text.set(mode="latex")
text.preamble(r"\usepackage{txfonts}")
figwidth = 12
gkey = key.key(pos=None, hpos=0.05, vpos=0.8)
xaxis = axis.linear(title=r"Time, \(t\)")
yaxis = axis.linear(title="Signal", min=-5, max=17)
g = graph.graphxy(width=figwidth, x=xaxis, y=yaxis, key=gkey)
plotdata = [graph.data.values(x=t, y=signal+offset, title=label) for label, signal, offset in (r"\(A(t) = \mathrm{square}(2\pi t/T)\)", A, 2.5), (r"\(B(t) = \mathrm{sawtooth}(\phi + 2 \pi t/T)\)", B, -2.5)]
linestyles = [style.linestyle.solid, style.linejoin.round, style.linewidth.Thick, color.gradient.Rainbow, color.transparency(0.5)]
plotstyles = [graph.style.line(linestyles)]
g.plot(plotdata, plotstyles)
g.text(10*unit.x_pt, 0.56*figwidth, r"\textbf{Cross correlation of noisy anharmonic signals}")
g.text(10*unit.x_pt, 0.33*figwidth, "Phase shift: input \(\phi = %.2f \,\pi\), recovered \(\phi = %.2f \,\pi\)" % (phase_shift/pi, recovered_phase_shift/pi))
xxaxis = axis.linear(title=r"Time Lag, \(\Delta t\)", min=-1.5, max=1.5)
yyaxis = axis.linear(title=r"\(A(t) \star B(t)\)")
gg = graph.graphxy(width=0.2*figwidth, x=xxaxis, y=yyaxis)
plotstyles = [graph.style.line(linestyles + [color.rgb(0.2,0.5,0.2)])]
gg.plot(graph.data.values(x=dt, y=xcorr), plotstyles)
gg.stroke(gg.xgridpath(recovered_time_shift), [style.linewidth.THIck, color.gray(0.5), color.transparency(0.7)])
ggtrafos = [trafo.translate(0.75*figwidth, 0.45*figwidth)]
g.insert(gg, ggtrafos)
g.writePDFfile("so-xcorr-pyx")

所以它可以很好地工作,即使是非常嘈杂的数据和不和谐的波形。


我已经尝试过了,即numpy.argmax(signal.correlate(listX,listY))),但它只返回列表中元素的数量... - Doa
奇怪。如果绘制自相关数组,它会是什么样子? - deprecated
1
顺便问一下,“不谐波”是指波形严格周期但不是正弦波吗?还是它们不是严格周期的?此外,这两个序列的周期是否相同? - deprecated
1
@Dow - 抱歉,我不理解你发布的数据文件。每个文件包含20,000行,每行由一个整数(行号)后跟100个浮点数组成。除了第一行外,每行中绝大多数(>95%)的浮点数都是相同的值(-80.0)。我们应该如何从这些文件中提取你的时间序列A和B? - deprecated
1
@Dow - 你的两个时间序列在某种意义上肯定是“同相”的,因为A中的峰值与B中的峰值重合。它们之间没有任何滞后。我还没有检查它们有多周期性。如果你对此感兴趣,可以在功率谱中寻找峰值 - 类似于 numpy.abs(numpy.fft.fft(A))**2 - deprecated
显示剩余4条评论

3

@deprecated的评论是关于纯代码Python解决方案的确切答案。这些评论非常有价值,但我认为我应该为在神经网络特定背景下寻找答案的人们添加一些说明。

当你计算大量神经元的平均膜电位时,相关性会相对较弱。你想要查看的主要是:单个组件之间的脉冲序列相关性、潜伏期或兴奋性(即突触效力)。可以通过查看电位超过某个阈值的点来相对容易地找到这些信息。当你给出脉冲序列时,Scipy的相关函数将展示神经元或神经元集合之间依赖关系的更详细图像,而不是实际电位。你还可以查看Brian的统计模块,它可以在这里找到:

http://neuralensemble.org/trac/brian/browser/trunk/brian/tools/statistics.py

至于相位差异,它可能是一种不充分的测量方法,因为神经元不是谐振子。如果你想要非常精确的相位测量,最好查看非谐振子的同步情况。描述这些类型振荡器的数学模型在神经元和神经网络背景下非常有用,那就是Kuramoto模型。有大量关于Kuramoto模型和Integrate-and-fire-synchronization的文档可供参考,所以我就不多说了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接