Найти разность фаз между двумя (негармоничными) волнами - PullRequest
13 голосов
/ 28 мая 2011

У меня есть два набора данных, в которых перечислены средние выходы напряжения двух сборок нейронных сетей в моменты времени 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, предпочтительно за все время моделирования.Поскольку две сборки вряд ли будут полностью в фазе, я хочу сравнить эту разность фаз с определенным порогом.

Это негармонические осцилляторы, и я не знаю их функции, только эти значения, поэтому у меня нетИдея, как определить фазу или соответствующую разность фаз.

Я делаю этот проект на Python, используя numpy и scipy (две сборки - это numpy массивы).

Любые предложения будут оченьприветствуется!

РЕДАКТИРОВАТЬ: добавлены графики

Пример файла данных для сборки 1

Пример файла данных для сборки 2

Вот график того, как выглядят два набора данных: Plot of two neural assemblies overlapping Plot of two neural assemblies seperate

Ответы [ 2 ]

22 голосов
/ 28 мая 2011

Возможно, вы ищете взаимную корреляцию:

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: Добавлен график примера.

Cross correlation of noisy anharmonic signals

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

Итакэто работает довольно хорошо, даже для очень шумных данных и очень ахармонических волн.

2 голосов
/ 08 июня 2011
Комментарии

@ deprecated являются точным ответом на вопрос, когда речь идет о чистом коде Python.Комментарии были очень ценными, но я чувствую, что я должен добавить некоторые заметки для людей, которые ищут ответ в конкретном контексте нейронных сетей.

Когда вы берете средний мембранный потенциал больших скоплений нейронов, как ясделал, корреляция будет относительно слабой.Прежде всего, вы хотите увидеть корреляцию между шиповыми поездами, задержкой или возбудимостью (то есть синаптической эффективностью) отдельных сборок.Это можно найти относительно легко, просто взглянув на точки, где потенциал превышает определенный порог.Функция корреляции Сципи на поездах с шипами покажет гораздо более детальную картину взаимозависимости между нейронами или нейронными ансамблями, когда вы даете ей поезда с шипами, в отличие от реальных потенциалов.Вы также можете взглянуть на модуль статистики Брайана, который можно найти здесь:

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

Что касается разности фаз, это, вероятно, неадекватная мера, поскольку нейроны не являются гармоническими осцилляторами.,Если вы хотите провести очень точные измерения фазы, лучше всего посмотреть на синхронизацию ингармонических осцилляторов.Математическая модель, которая описывает эти виды осцилляторов, которая очень полезна в контексте нейронов и нейронных сетей, является моделью Курамото.Для модели Kuramoto и встроенной синхронизации с огнем имеется обширная документация, поэтому я оставлю это на этом.

...