如何对保留峰值的信号进行下采样?

4
我正在分析一个以200Hz采样的信号,时长为6-8秒,其中重要部分是最多持续1秒的尖峰。例如,可以想象地震...
我需要将这个信号下采样2倍。我尝试了:
from scipy import signal

signal.decimate(mysignal, 2, ftype="fir")
signal.resample_poly(mysignal, 1, 2)

我使用这两个函数得到了相同的结果:信号被重新采样,但是峰值(包括正负的)被削弱了。

是我使用的函数有问题,还是需要传递一个自定义的FIR滤波器?


1
每个尖峰有多少样本? - DrBwts
你是实时采样还是事后分析数据? - Anteino
如果您使用scipy.signal.resample,给定x、num、t和axis参数,然后调整窗口参数会怎么样呢? - Patol75
@Anteino:分析中 - Marco Sulla
@Patol75:据我所知,该函数用于周期信号,而我没有周期信号。 - Marco Sulla
显示剩余4条评论
4个回答

4

注意

如果你的信号频率达到了采样频率的极限(奈奎斯特-香农采样定理),那么降采样将总是损坏信号。在你的情况下,你的尖峰类似于非常高频的信号,因此你需要非常高的采样频率。

(例如:你有三个点,中间一个有尖峰。你想将其降采样为2个点。把尖峰放在哪里?无处可放,因为你的样本不足。)

尽管如此,如果你真的想要降采样信号,并且仍然想要(或多或少地准确地)保留特定点(在你的情况下是尖峰),你可以尝试以下方法,该方法“保存”你的尖峰,降低采样信号,然后只在相应的降采样信号位置上应用“保存”的尖峰。

操作步骤:

1) 获取尖峰,或者换句话说,本地最大值(或最小值)。

例如:Pandas 找到本地最大值和最小值

2) 降低采样信号

3) 使用第1步得到的尖峰,替换相应的降采样位置上的值

(要考虑到你的信号将会受到损坏。你不能降低采样而不失去由一个或两个点表示的尖峰)

编辑

示例说明

这是一个保留尖峰的示例。它只是一个示例,现在它不能用于负值。

enter image description here

import numpy as np
import matplotlib.pyplot as plt
from collections import deque


t = np.arange(1000)/100
y = np.sin(t*2*3.14)
y[150]=5
y[655]=5
y[333]=5
y[250]=5

def downsample(factor,values):
    buffer_ = deque([],maxlen=factor)
    downsampled_values = []
    for i,value in enumerate(values):
        buffer_.appendleft(value)
        if (i-1)%factor==0:
            #Take max value out of buffer
            # or you can take higher value if their difference is too big, otherwise just average
            downsampled_values.append(max(buffer_))
    return np.array(downsampled_values)

plt.plot(downsample(10,y))
plt.show()

enter image description here


“在计数时要考虑到信号会受损。你不能降采样而不丢失峰值。” 那么你的意思是正确答案只是“你不能”? :) - Marco Sulla
想象一下你有三个点,中间的一个有尖峰。现在将其降采样为两个点。你要在哪里画尖峰?你可以将尖峰分配给点1或点2(这有点损坏信号),或者你可以将其绘制到两个点上(也没有意义),或者你根本不画它,并且你只是接受奈奎斯特-香农采样定理是真实的。对于数据而言,你不能同时坐在两把椅子上。 - Martin
@MarcoSulla 我已经编辑了答案并提供了示例。这只是保留峰值的示例。您应该按照我在第2步中指出的方法提取峰值,而不是像我所做的那样。 - Martin
1
好的,如果你在开头加上“你不能这样做,信号会被损坏。但是如果你真的想忽略这个问题......”或类似的话,我会接受你的回答 :) - Marco Sulla
@MarcoSulla 它在那里。 - Martin

0
正如@Martin所指出的那样,尖峰包含高频成分。将您的信号转换为旋转参考系(即添加/删除基频率)。这有效地将您的信号移动了最大所需频率的一半,并且您可以以半速率进行采样。

0

如果您对别名不太挑剔,那么您可以只取每第二个(第N个)样本的最大值。

def take(N, samples):
    it = iter(samples)
    for _ in range(len(samples)/N):
        yield max(it.next() for _ in range(N))

理解这个:

import random
random.seed(1)

a = [random.gauss(10,3) for _ in range(100)]

for c in take(5, a):
    print c

0

如果您的硬件支持,可以以最高可能的频率进行采样,但仅在振幅或时间差异达到最小值时保存一个点。这样,您的实际数据点将根据任一标准进行过滤。当信号没有真正变化时,您就有了所需的采样率,并且峰值也仍然被记录。

假设data包含您的恒定采样率采样点。在此算法结束时,列表saved将包含您的data中所有重要的[时间戳,采样点]条目:

DIVIDER = 5
THRESHOLD = 1000

saved = [ [0, data[0]] ]

for i in range(1, len(data)):
    if( (i % DIVIDER == 0) || (abs(data[i] - data[i - 1]) > THRESHOLD) ):
        saved.append([ i, data[i] ])

不必查看两个采样点之间的振幅差异,您也可以通过对此简单代码进行微小更改,保存所有高于或低于某个振幅的数据点。


我无法更改采样率。 - Marco Sulla
但是,您仍然可以将相同的技术应用于获取的数据。 您可以保存每个其他样本以获得减半的采样率。 如果您仍然检查某个阈值的每个中间值,则只能保存那些重要的中间点。 如果您将采样率除以4、5或10,也可以这样做。 - Anteino
关于别名呢? - Marco Sulla
关于这个问题呢?你想要降采样还是不降采样? - Anteino
1
然后,您可以将DIVIDER设置为2,并在您拥有的数据上运行我提供的算法。 saved列表将包含您需要的数据,但不以固定的采样率。这就是为什么我还保存时间戳的原因。您不能在整个数据中保持恒定的采样率并保留所有峰值。您必须做出让步。在峰值周围具有局部较高的采样率似乎对我来说是最好的折衷方案。 - Anteino
显示剩余4条评论

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