检测信号的谷值

信息处理 信号分析 过滤器设计 数字滤波器 阈值
2022-02-03 06:07:10

我有直接来自传感器的原始值(动态)。这些值来自安装在奶牛脖子上的可穿戴传感器。当牛反刍(意味着它咀嚼从它的第二个胃带回来的食物)时,会产生某种具有某种特定幅度和频率的加速度值(咀嚼持续时间大多在 800 毫秒到 1200 毫秒之间)。每次反刍时间为 30 至 120 秒,奶牛每天反刍约 10 小时。

我对这些值进行了快速计算,最终得到了如下图所示的图表。

信号的标准偏差

我希望能够检测到信号何时下降(如突出显示的峰值),因为它代表了一个反刍期。图中的下降代表了奶牛的食团事件(意味着奶牛只是将咀嚼过的食物变浅并带回 [从胃中] 重新咀嚼的新食物)。

我尝试使用阈值方法(如果信号低于设定阈值)来做到这一点,但它无法始终正确运行。这是因为:

1)信号强度在白天和不同传感器之间略有变化,例如。在图像上,负峰不低​​于黑色水平线,这是我的阈值。因此,我有错误检测(根本没有检测到它们)。如果我增加阈值,我会做错误的检​​测,因为信号中的许多其他点可能会通过它。

2)当信号有点嘈杂时,我会做错检测或根本没有检测到。例如,信号的第 9 个黄点应该以某种方式被检测为谷值,但它远高于阈值。当然,它可能会被错误地检测到,因为它与附近的一些点具有相同的幅度。

有人知道我如何及时检测到这些点(下降)吗?

注意: 这些数据是实时的,它们没有存储在某个地方。因此,我必须能够以某种方式动态检测信号的下降,而无需对其未来值有任何了解(当然,我可以有一些小的历史记录——比如说最后 200 个值或其他东西)。

额外信息: 这些数据值实际上来自 3 轴加速器传感器。我计算它们的大小 (sqrt(x^2 + y^2 + z^2)),它们偏离大约 1g,然后我得到最后一秒的移动标准偏差(62.5 值)。这就是上图中显示的内容。黄色点的偏差约为 0.01g。

进一步: 在被一些用户询问后,我还附上了原始信号的图像(只是其中的一小部分)。用黄色标记感兴趣的区域(在幅度上)。其余 3 个图是 X、Y、Z(图例存在于图的右上角)。

原始信号

另外,我附上了一个超链接,您可以在其中下载 CSV 格式的示例信号。格式如下:第 1、第 2、第 3 列是 X、Y 和 Z 轴加速度计值。第 4 列是它们的大小 (sqrt(x^2 + y^2 + z^2)),如果需要,您也可以手动计算。

https://1drv.ms/f/s!Au5-DmkSvYQzgZlLo2KJ_UBAVeYDWw

有 4 个非常好的信号的文件。Good3s.csv 的开头包含一些小垃圾(可以丢弃大约 10000 个第一个值)。Good4e.csv 最后也有相同的内容。还有 2 个非常嘈杂的信号文件,如果您喜欢硬核情况,可以解析它们。

3个回答

首先,在 dsp.stackexchange 上发布此内容可能会更好。那是一个更专业的团队,一直在做这样的事情。

就您的问题而言,这里有几个选项。

一种是机器学习方法例如,通过获取一堆数据并手工标记好与坏的点来创建一个训练集(就像你在上面所做的那样)。然后拿一个人工神经网络,输入训练数据并教它识别你想要的模式。

另一种方法可能是采用统计过程控制方法。那里有很多工具可以检测何时出现异常情况。

另一种方式可能是浮动阈值。计算最后 X 个样本的平均值,如果信号下降超过 Y 低于该平均值,则称其为坏信号。还可以计算最后 X 个样本的标准偏差,如果信号下降超过 Z std devs 则将其回调。

或者,可能只是对信号进行高通滤波以消除缓慢漂移的平均值,然后您可以使用固定阈值。

我没有仔细阅读整个问题,因为我现在没有时间,但是您是否尝试过某种形式的稳健峰值检测?参见例如https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks.html

然后您可以设置参数,例如最小(和最大)距离、突出度、最小高度。如果您寻找最小值,只需翻转信号的符号即可。

因此,您的基本任务是检测某些振动幅度低于阈值的“安静”部分。

在你想检测到它之前,你能对“静默”阶段的长度做出假设吗?分析您的数据后,我发现大多数静默阶段的持续时间为 ca。200 个样本,每 3000 个样本重复一次。你能对重复做出假设吗?(例如:在一次“检测”之后,2000 个样本不能再有一个”)

下面我添加了我当前的 GNU Octave 代码(恕我直言,它非常适合原型算法、设计过滤器、分析数据等)

# https://dsp.stackexchange.com/questions/51269/detect-valleys-of-a-signal
# https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods

graphics_toolkit fltk

pkg load image  ## for "nlfilter"
pkg load signal ## for "butter"

FS = 62.5;  # in the question "of the last second (62.5 values)"

fns = glob ("*.csv");

k = 1;

d = dlmread (fns{k}, ";");

## calculate magnitude;
mag = sqrt (sumsq (d(:, 1:3), 2)) - 1;

## remove the slow varying trend
[b, a] = butter (8, 0.01);
mag -= filter (b, a, mag);

## find parts where magitude is below +/- thres
thres = 0.04;
q = abs (mag) < thres;

## ensure, that the first and last sample never is "quiet"
q(1) = q(end) = false;

## starts of quiet part
qs = find(diff(q) == 1);

## ends of quiet part
qe = find(diff(q) == -1);

## length of the quiet parts
len = qe - qs;

## only consider parts longer than 2s
idx = find (len > 2 * FS);

plot (mag)

hold on
# draw line above detection
line ([qs(idx) qe(idx)].', repmat (thres, 2, numel (idx)), "color", "red", "linewidth", 5)
hold off

Good.csv 检测

红线是“检测”

PS:我想你知道https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods但以防万一