Python 估计两个时间序列之间的小时间偏移

Python 估计两个时间序列之间的小时间偏移,python,statistics,scipy,signal-processing,correlation,Python,Statistics,Scipy,Signal Processing,Correlation,我有两个时间序列,我怀疑它们之间有时间偏移,我想估计这个时间偏移 这一问题以前曾在: 但在我的例子中,时间偏移小于数据的分辨率。例如,数据以每小时一次的分辨率提供,时间偏移仅为几分钟(见图) 这是因为用于测量其中一个系列的数据记录器的时间偏移了几分钟 有没有算法可以估计这种偏移,最好不用插值 这是一个非常有趣的问题。这里有一个使用傅里叶变换的部分解的尝试。这取决于数据具有适度的周期性。我不确定它是否适用于您的数据(端点的导数似乎不匹配) 将numpy导入为np X=np.linspace(0,2

我有两个时间序列,我怀疑它们之间有时间偏移,我想估计这个时间偏移

这一问题以前曾在: 但在我的例子中,时间偏移小于数据的分辨率。例如,数据以每小时一次的分辨率提供,时间偏移仅为几分钟(见图)

这是因为用于测量其中一个系列的数据记录器的时间偏移了几分钟

有没有算法可以估计这种偏移,最好不用插值


这是一个非常有趣的问题。这里有一个使用傅里叶变换的部分解的尝试。这取决于数据具有适度的周期性。我不确定它是否适用于您的数据(端点的导数似乎不匹配)

将numpy导入为np
X=np.linspace(0,2*np.pi,30)#一些X值
def yvals(x):
返回np.sin(x)+np.sin(2*x)+np.sin(3*x)
Y1=yvals(X)
Y2=yvals(X-0.1)#移动的y值
#傅里叶变换两个级数
FT1=np.fft.fft(Y1)
FT2=np.fft.fft(Y2)
#从分析上可以看出,系数中的相移会导致
#`exp(-1.j*N*T\d)的乘法因子`
#无法接受第0个元素,因为这是0的除法。分析而言,
#根据L'hopital的规则,除以0是可以的,但计算机不懂微积分:)
打印np.log(FT2[1://FT1[1:])/(-1.j*np.arange(1,len(X)))
对打印输出的快速检查表明,频率最高 幂(N=1,N=2)给出了合理的估计,如果你看一下 绝对值(np.absolute),尽管我无法解释为什么会这样


也许更熟悉数学的人可以从这里得到更好的答案…

您提供的一个链接有正确的想法(事实上,我在这里做的事情几乎相同)

它具有以下输出:

Preset shift:  -3
Calculated shift:  -2.99

可能需要检查一下

  • 请注意,相关性的argmax()表示对齐的位置,必须按
    b-a=10-0=10
    和N的长度进行缩放,以获得实际值

    检查correlate的源并不完全清楚从sigtools导入的函数的行为。对于大型数据集,循环相关(通过快速傅立叶变换)比直接方法快得多。我怀疑这就是sigtools中实现的东西,但我不能确定。在我的python2.7文件夹中搜索该文件时,只返回已编译的C pyd文件。

    我已成功使用(在awgn通道中)匹配过滤器方法,该方法在索引n处给出峰值能量m[n];然后将二次多项式f(n)拟合到m[n-1],m[n],m[n+1],并通过设置f'(n)==0来找到最小值


    响应不一定是绝对线性的,特别是当信号的自相关在m[n-1],m[n+1]处不消失时。

    这是一个非常有趣的问题。最初,我打算提出一个类似于user948652的基于互相关的解决方案。但是,根据您的问题描述,该解决方案存在两个问题:

    Unknown shift:  0.0695701123582
    Found   shift:  0.0696105501967
    
  • 数据的分辨率大于时间偏移,并且
  • 有时,预测值和测量值之间的相关性很低
  • 由于这两个问题,我认为直接应用互相关解决方案实际上可能会增加您的时间偏移,特别是在预测值和测量值彼此相关性非常低的日子

    在我上面的评论中,我问你是否有任何事件发生在这两个时间序列中,你说你没有。然而,基于您的领域,我认为您实际上有两个:

  • 日出
  • 日落
  • 即使信号的其余部分相关性很差,日出和日落也应该有一定的相关性,因为它们将从夜间基线单调增加/减少。所以这里有一个潜在的解决方案,基于这两个事件,它应该最小化所需的插值,并且不依赖于弱相关信号的互相关

    1。查找大致的日出/日落

    这应该很简单,只需获取高于夜间平面线的第一个和最后一个数据点,并将其标记为大致的日出和日落。然后,我将重点关注该数据,以及两侧的点,即:

    width=1
    sunrise_index = get_sunrise()
    sunset_index = get_sunset()
    
    # set the data to zero, except for the sunrise/sunset events.
    bitmap = zeros(data.shape)
    bitmap[sunrise_index - width : sunrise_index + width] = 1
    bitmap[sunset_index - width : sunset_index + width] = 1
    sunrise_sunset = data * bitmap 
    
    有几种方法可以实现
    获取日出()
    获取日落()。我会使用,在一个特定的值上设置阈值,然后取高于该值的第一个和最后一个点。您还可以从大量文件中读取夜间数据,计算平均值和标准偏差,并查找超过夜间数据的第一个和最后一个数据点,例如,
    0.5*st_dev
    。您还可以执行某种基于群集的模板匹配,特别是在不同类别的白天(即晴天、部分多云和非常多云)具有高度定型的日出/日落事件时

    2。重新采样数据

    我不认为没有插值就没有办法解决这个问题。我会使用重采样的数据,以更高的采样率比转移。如果班次以分钟为单位,则将采样增加到1分钟或30秒

    num_samples = new_sample_rate * sunrise_sunset.shape[0]
    sunrise_sunset = scipy.signal.resample(sunrise_sunset, num_samples)
    
    或者,我们可以使用三次样条插值数据(请参见)

    3。高斯卷积

    因为有一些插值,所以我们不知道实际的日出和日落是如何精确预测的。所以,我们可以用高斯函数来卷积信号,来表示这种不确定性

    gaussian_window = scipy.signal.gaussian(M, std)
    sunrise_sunset_g = scipy.signal.convolve(sunrise_sunset, gaussian_window)
    
    4。互相关

    使用互相关法
    gaussian_window = scipy.signal.gaussian(M, std)
    sunrise_sunset_g = scipy.signal.convolve(sunrise_sunset, gaussian_window)
    
    np.sqrt((X1-X2+delta_x)**2+(Y1-Y2)**2).sum()
    
    import numpy as np
    
    def yvals(x):
        return np.sin(x)+np.sin(2*x)+np.sin(3*x)
    
    dx = .1
    unknown_shift = .03 * np.random.random() * dx
    
    X1  = np.arange(0,2*np.pi,dx)  #some X values
    X2  = X1 + unknown_shift
    
    Y1 = yvals(X1)
    Y2 = yvals(X2) # shifted Y
    Y2 += .1*np.random.normal(size=X1.shape)  # now with noise
    
    def err_func(p):
        return np.sqrt((X1-X2+p[0])**2+(Y1-Y2)**2).sum()
    
    from scipy.optimize import fmin
    
    p0 = [0,] # Inital guess of no shift
    found_shift = fmin(err_func, p0)[0]
    
    print "Unknown shift: ", unknown_shift
    print "Found   shift: ", found_shift
    print "Percent error: ", abs((unknown_shift-found_shift)/unknown_shift)
    
    Optimization terminated successfully.
             Current function value: 4.804268
             Iterations: 6
             Function evaluations: 12
    Unknown shift:  0.00134765446268
    Found   shift:  0.001375
    Percent error:  -0.0202912082305
    
    import numpy as np
    from scipy.interpolate import interp1d
    from scipy.optimize import leastsq
    
    def yvals(x):
        return np.sin(x)+np.sin(2*x)+np.sin(3*x)
    
    dx = .1
    X = np.arange(0,2*np.pi,dx)
    Y = yvals(X)
    
    unknown_shift = np.random.random() * dx
    Y_shifted = yvals(X + unknown_shift)
    
    def err_func(p):
        return interp1d(X,Y)(X[1:-1]+p[0]) - Y_shifted[1:-1]
    
    p0 = [0,] # Inital guess of no shift
    found_shift = leastsq(err_func,p0)[0][0]
    
    print "Unknown shift: ", unknown_shift
    print "Found   shift: ", found_shift
    
    Unknown shift:  0.0695701123582
    Found   shift:  0.0696105501967
    
    Y_shifted += .1*np.random.normal(size=X.shape)
    
    Unknown shift:  0.0695701123582
    Found   shift:  0.0746643381744
    
    X = np.arange(0,200*np.pi,dx)
    
    Unknown shift:  0.0695701123582
    Found   shift:  0.0698527939193