如何对信号保持尖峰进行下采样?
Posted
技术标签:
【中文标题】如何对信号保持尖峰进行下采样?【英文标题】:How to downsample a signal preserving spikes? 【发布时间】:2020-03-24 09:14:33 【问题描述】:我正在分析一个以 200Hz 采样 6-8 秒的信号,重要的部分是尖峰,最长持续 1 秒。以地震为例……
我必须将信号下采样 2 倍。我试过了:
from scipy import signal
signal.decimate(mysignal, 2, ftype="fir")
signal.resample_poly(mysignal, 1, 2)
我使用这两个函数得到了相同的结果:信号被重新采样,但尖峰,正负尖峰,都减少了。
我错了函数,还是我必须通过自定义 FIR 滤波器?
【问题讨论】:
每个尖峰有多少个样本? @DrBwts:信号的频率为 200Hz,通常在不到 1 秒的时间内出现尖峰。信号最长可持续 8 秒。 您是在现场采样还是只是事后分析数据? 如果你使用scipy.signal.resample,给出x、num、t和axis然后玩window参数呢? @Anteino:分析 【参考方案1】:注意
如果您的信号频率达到采样频率的极限(奈奎斯特-香农采样定理),下采样将始终损坏信号。在您的情况下,您的尖峰类似于非常高频的信号,因此您还需要非常高的采样频率。
(示例:您有 3 个点,中间一个有尖峰。您想将其下采样到 2 个点。尖峰放在哪里?无处可去,因为您的样本用完了。)
尽管如此,如果您真的想对信号进行下采样,并且仍然想保留(或多或少准确地)特定点(在您的情况下是尖峰),您可以尝试低于姿态,这样可以节省' 您的尖峰,对信号进行下采样,然后才在相应的下采样信号位置应用“保存的”尖峰。
步骤:
1) 获得尖峰,或者换句话说,局部最大值(或最小值)。
示例:Pandas finding local max and min
2) 对信号进行下采样
3) 使用从 1) 中得到的那些尖峰,替换相应的下采样值
(算上你的信号会被损坏的事实。你不能在不丢失由一两个点表示的尖峰的情况下进行下采样)
编辑
示例
这是如何保持尖峰的示例。它只是示例,因为它现在不适用于负值
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()
【讨论】:
>。所以你说正确的答案只是“你不能”? :) 假设您有 3 个点,而中间的点有尖峰。现在下采样两个 2 点。你要在哪里画尖峰?您可以将尖峰分配给点 1 或点 2(这会破坏信号),或者您可以将它绘制到两个点(也没有意义),或者您根本不绘制它,您只需接受 Nyquist -香农采样定理是真实的。有了数据,你不能同时坐在两把椅子上 @MarcoSulla 我用示例编辑了答案。它只是如何保持尖峰的示例。而不是像我那样做,你应该像我在 2) 步骤中指出的那样提取尖峰 好吧,我想我会接受你的答案,如果你在开头添加“你不能,信号会被损坏。但如果真的想忽略这个......”或类似的东西:) @MarcoSulla 它在那里【参考方案2】:如果您的硬件支持,您可以以尽可能高的频率进行采样,但仅在达到最小幅度差异或时间差异时才保存一个点。这样,您的实际数据点将根据任一标准进行过滤。当信号中没有真正发生变化时,您就会获得所需的采样率,并且峰值仍然会被记录。
让我们假设 data 包含以恒定采样率的采样点。在此算法结束时,列表 saved 将包含您的 data 的所有重要 [timestamp, sample_point] 条目:
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] ])
除了查看两个采样点之间的幅度差异,您还可以只保存位于某个幅度之上或之下的所有数据点,并在这段简单的代码中进行微小的更改。
【讨论】:
我无法更改采样率。 但是您仍然可以将相同的技术应用于获取的数据。您可以保存所有其他样本以获得减半的采样率。如果您仍然检查某个阈值的每个中间值,则只能保存那些重要的中间点。如果将采样率除以 4、5 或 10,您也可以这样做。 我会写一小段代码稍后演示。 别名怎么样? 然后您可以将 DIVIDER 设置为 2 并根据您拥有的数据运行我给出的算法。 已保存 列表将包含您需要的数据,但不是以固定的采样率。这就是为什么我还要保存时间戳。您不能在整个数据中保持恒定的采样率并且保留所有尖峰。你必须做出让步。对我来说,在峰值附近有一个局部更高的采样率似乎是最好的折衷方案。【参考方案3】:如果您对混叠不太挑剔,可以只取每秒 (Nth) 个样本的最大值。
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
【讨论】:
【参考方案4】:正如@Martin 指出的那样,尖峰包含高频成分。将您的信号转换为旋转的参考系(即添加/删除基频)。这有效地将您的信号移动了最大所需频率的一半,并且您可以以一半的速率进行采样。
【讨论】:
以上是关于如何对信号保持尖峰进行下采样?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 python 或 MATLAB 中对 ECG 信号进行上采样和下采样?
如何解决GD32F103在重新上电AD采样时偶尔有6个码的跳动
如何通过 2x2 平均内核对 pandas 数据帧进行下采样