如何对信号保持尖峰进行下采样?

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 数据帧进行下采样

[离散时间信号处理学习笔记] 11. 连续时间信号的采样与重构

VoxelGrid体素滤波器对点云进行下采样