仅基于您发布的两个示例,我有几个不同的建议:阈值或模板匹配。
门槛
因为您提到信号中的垂直下降是相对恒定的,特别是对于您检测到的第一个事件,似乎您可以使用阈值方法,您可以将事件放置在第一次出现超过某个阈值的信号时兴趣。例如,放置第一个事件(在 Python 中,并假设您的测量数据存在于包含 xy 对的元组序列中):
def detect_onset_event(measurements):
armed = False
for offset, (timestamp, value) in enumerate(measurements):
if value > 90:
armed = True
if armed and value < 85:
return offset
return -1 # failure condition, might want to raise ValueError()
因此,我们在信号高于 90 后降至低于 85 的第一个样本偏移处触发。
您可以为第二个事件做类似的事情,但看起来对那个事件很重要的信号电平可能不太明确。取决于您的应用和测量数据。这是一个很好的例子,说明阈值方法不太好——它们可能很脆弱并且依赖于硬编码的值。但是,如果您的测量非常有规律,那么这可以很好地工作,只需很少的编码工作。
模板
在这种方法中,您可以为每个感兴趣的信号事件创建一个模板,然后将模板与您的信号进行卷积以识别信号的相似区域。
import numpy
def detect_twopeak_event(measurements, template):
data = numpy.asarray(measurements) # convert to numpy array
activations = numpy.convolve(
data[:, 1], # convolve over all "value" elements
template)
return activations.argmax()
在这里,您需要创建构成您要检测的事件的样本测量值列表 - 例如,您可以从示例信号的两个峰值区域中提取测量值以用作模板。然后,通过将此模板与测量数据进行卷积,您将获得测量与模板的相似程度的指标。您可以只返回最佳匹配的索引(如上面的代码中所示)或将这些相似性估计传递给其他进程以选择“最佳”。
有很多方法可以创建模板,但我认为最有前途的方法之一是使用来自标记训练事件的一组邻域的平均值。也就是说,假设您有一个与给定事件发生的样本偏移配对的信号数据库。您可以通过平均围绕这些标记事件的窗口区域来创建模板:
def create_mean_template(signals, offsets, radius=20):
w = numpy.hanning(2 * radius)
return numpy.mean(
[s[o-radius:o+radius] * w for s, o in zip(signals, offsets)],
axis=0)
这已成功用于许多信号处理领域,如面部识别(例如,您可以通过对一组标记的眼睛周围的像素进行平均来为眼睛创建模板)。
模板方法开始失败的一个地方是,如果您的信号有很多看起来像模板的区域,但这些区域与您想要检测的事件不对应。处理这个问题很棘手,因此如果您的事件附近发生了独特的信号模式,则模板方法效果最好。
模板方法失败的另一种方式是,如果您的测量数据包含,例如,一个有趣的双峰区域,但出现的频率与您用作模板的样本不同。在这种情况下,您可以通过在时频域而不是时幅域中工作,使您的模板对轻微的频率变化更加稳健。在那里,无需制作与您感兴趣的幅度变化的时间模式相对应的 1D 模板,您可以对测量结果运行窗口 FFT,然后提出与 k 维频率变化相对应的 kD 模板。您感兴趣的事件周围的区域。
希望这些建议中的一些有用!