如何将两个时间序列与差距和不同时基相关联?

时间:2011-02-27 01:27:35

标签: python r numpy signal-processing accelerometer

我有两个时间序列的3D加速度计数据具有不同的时基(时钟在不同的时间开始,在采样时间内有一些非常轻微的蠕变),以及包含许多不同大小的间隙(由于与之相关的延迟)写入单独的闪存设备)。

我使用的加速度计价格便宜GCDC X250-2。我正在以最高增益运行加速度计,因此数据具有显着的本底噪声。

时间序列每个都有大约200万个数据点(超过一小时,512个样本/秒),并包含大约500个感兴趣的事件,其中典型事件跨越100-150个样本(每个200-300毫秒)。其中许多事件都受到闪存写入期间数据中断的影响。

因此,数据不是原始的,甚至不是很漂亮。但我的眼球检查显示它清楚地包含了我感兴趣的信息。(如果需要,我可以发布情节。)

加速度计处于相似的环境中,但只是适度耦合,这意味着我可以通过眼睛判断哪些事件与每个加速度计匹配,但到目前为止我在软件中这样做是不成功的。由于物理限制,设备也安装在不同的方向,轴不匹配,但它们尽可能接近正交。因此,例如,对于3轴加速度计A& B,+ Ax映射到-By(上下),+ Az映射到-Bx(左右),+ Ay映射到-Bz(前后)。

我最初的目标是将垂直轴上的冲击事件关联起来,尽管我最终希望a)自动发现轴映射,b)关联映射的aces上的活动,以及c)提取两个加速度计之间的行为差​​异(如扭曲或弯曲)。

时间序列数据的本质使得Python的numpy.correlate()无法使用。我也看过R的动物园套餐,但没有取得进展。我已经在信号分析的不同领域寻求帮助,但我没有取得任何进展。

任何人都有任何关于我能做什么的线索,或者我应该研究的方法?

2011年2月28日更新:添加了一些显示数据示例的图here

5 个答案:

答案 0 :(得分:4)

我对你的问题的解释:鉴于两个非常长的,嘈杂的时间序列,找到一个与一个信号中的大“凸起”匹配的移位到另一个信号中的大凸起。

我的建议:对数据进行插值,使其均匀间隔,整流和平滑数据(假设快速振荡的相位不感兴趣),并做一次一点的互相关(假设一个小的移位)将排列数据。)

import numpy
from scipy.ndimage import gaussian_filter
"""
sig1 and sig 2 are assumed to be large, 1D numpy arrays
sig1 is sampled at times t1, sig2 is sampled at times t2
t_start, t_end, is your desired sampling interval
t_len is your desired number of measurements
"""

t = numpy.linspace(t_start, t_end, t_len)
sig1 = numpy.interp(t, t1, sig1)
sig2 = numpy.interp(t, t2, sig2)
#Now sig1 and sig2 are sampled at the same points.

"""
Rectify and smooth, so 'peaks' will stand out.
This makes big assumptions about your data;
these assumptions seem true-ish based on your plots.
"""
sigma = 10 #Tune this parameter to get the right smoothing
sig1, sig2 = abs(sig1), abs(sig2)
sig1, sig2 = gaussian_filter(sig1, sigma), gaussian_filter(sig2, sigma)

"""
Now sig1 and sig2 should look smoothly varying, with humps at each 'event'.
Hopefully we can search a small range of shifts to find the maximum of the 
cross-correlation. This assumes your data are *nearly* lined up already.
"""
max_xc = 0
best_shift = 0
for shift in range(-10, 10): #Tune this search range
    xc = (numpy.roll(sig1, shift) * sig2).sum()
    if xc > max_xc:
        max_xc = xc
        best_shift = shift
print 'Best shift:', best_shift
"""
If best_shift is at the edges of your search range,
you should expand the search range.
"""

答案 1 :(得分:1)

如果数据包含每个时间序列中不同大小的未知大小的间隙,那么我会放弃尝试关联整个序列,而是尝试在每个时间序列上交叉关联短窗口对,比如重叠两倍的窗口典型事件的长度(300个样本长)。在所有可能性中找到潜在的高互相关匹配,然后对潜在匹配强制执行顺序排序约束,以获得匹配窗口的序列。

从那里你有更小的问题,更容易分析。

答案 2 :(得分:0)

听起来你想最小化一对值的函数(Ax'+ By)+(Az'+ Bx)+(Ay'+ Bz):即时间偏移量:t 0 和时间比例因子:t r 。其中Ax'= t r *(Ax + t 0 )等。

我会研究SciPy的双变量optimize函数。我会使用mask或暂时将数据(例如Ax'和By)置于“间隙”上(假设可以通过编程方式确定间隙)。

为了提高过程的效率,首先对A和B进行粗略采样,但要设置与您的采样相称的fmin(或您选择的任何优化器)的精度。然后继续对整个数据集进行逐步精细采样的窗口,直到窗口变窄并且不进行下采样。<​​/ p>

编辑 - 匹配轴

关于尝试识别哪个轴与给定轴共线,并且不了解数据特征的问题,我可以指出类似的问题。查看pHashthis帖子中列出的任何其他方法,以帮助识别类似的波形。

答案 3 :(得分:0)

这不是技术上的答案,但它可能会帮助你提出一个:

  • 将绘图转换为图像,并将其粘贴到像gimp或photoshop
  • 这样的图像程序中
  • 只要有间隙
  • ,就将图分解成离散图像
  • 将第一系列地块放在水平线上
  • 将第二个系列放在它下面的水平线上
  • 直观地识别第一个相关事件
  • 如果两个事件没有垂直排列:
    • 选择左侧更左侧的实例以及该行右侧的所有内容
    • 将这些东西拖到右边,直到它们排成一行

这几乎就是音频编辑器的工作方式,因此如果您将其转换为简单的音频格式(如未压缩的WAV文件),您可以直接在Audacity中操作它。 (当然,这听起来很可怕,但你可以很容易地移动数据图。)

实际上,audacity也有一种叫做nyquist的脚本语言,所以如果你不需要程序检测相关性(或者你至少愿意推迟那个步骤)你可以使用audacity的标记和nyquist的某种组合来自动化对齐,并在标记相关点后以您选择的格式导出干净的数据。

答案 4 :(得分:0)

我的猜测是,你必须手动建立一个偏移表来对齐系列之间的“匹配”。以下是获取这些匹配的方法示例。我们的想法是左右移动数据直到它排成一行,然后调整比例直到它“匹配”。试一试。

library(rpanel)

#Generate the x1 and x2 data
n1 <- rnorm(500)
n2 <- rnorm(200)
x1 <- c(n1, rep(0,100), n2, rep(0,150))
x2 <- c(rep(0,50), 2*n1, rep(0,150), 3*n2, rep(0,50))

#Build the panel function that will draw/update the graph
lvm.draw <- function(panel) {
       plot(x=(1:length(panel$dat3))+panel$off, y=panel$dat3, ylim=panel$dat1, xlab="", ylab="y", main=paste("Alignment Graph   Offset = ", panel$off, "   Scale = ", panel$sca, sep=""), typ="l")
       lines(x=1:length(panel$dat3), y=panel$sca*panel$dat4, col="red")
       grid()
       panel
}

#Build the panel
xlimdat <- c(1, length(x1))
ylimdat <- c(-5, 5)
panel <- rp.control(title = "Eye-Ball-It", dat1=ylimdat, dat2=xlimdat, dat3=x1, dat4=x2, off=100, sca=1.0, size=c(300, 160))
rp.slider(panel, var=off, from=-500, to=500, action=lvm.draw, title="Offset", pos=c(5, 5, 290, 70), showvalue=TRUE)
rp.slider(panel, var=sca, from=0, to=2, action=lvm.draw, title="Scale", pos=c(5, 70, 290, 90), showvalue=TRUE)