隔离信号中的 'active' 个部分

Isolating 'active' parts in signal

我有一个数据集,其中包含来自按下按钮的信号。现在在数据涵盖的整个时间段内,也有噪音。数据本身只是一个向量,其中包含对应于正弦函数线性组合的数字。

我想隔离按下按钮的部分。所以我首先想到对噪音使用一定的阈值。噪音永远不会高于 0.4,因此这将是一个很好的阈值。所以我的计划是创建新的向量,每个向量都包含按下单个按钮的时间段的数据,但我不知道该怎么做。

我想我需要 运行 超过矢量的代码,检查是否克服了 0.4 的阈值,然后将数据存储到一个新的矢量中,直到至少 x许多条目再次低于阈值。

这个想法行得通吗?我不知道如何开始这项检查,感谢任何帮助。

仅供参考:最后我想使用 fft 提取正弦函数,但不使用 signal processing toolbox.

编辑

我现在创建了(部分)工作代码:

z= [0 0.1 0.4 0.2 0.8 0.3 0.6 0.3 0.3 0.2 0.1 0.2 0.0 0.3 0.4 0.5 0.6 0.3 0.3 0.2 0.1 0.0];
zN = length(z);
y=[;];
m=0;
j=0;
i=1;
while i < zN
    if z(i) >= 0.4
        m=m+1;
        k=0;
        for j = i:zN
            k=k+1;
            y(m,k) = z(j);
            if z(j) <0.4 && z(j+1)<0.4 && z(j+2)<0.4
                i=i+j+3;
                break
            end
        end
    end
i=i+1;    
end

正如所希望的那样,返回一个矩阵 y=[0.4 0.2 0.8 0.3 0.6 0.3; 0.4 0.5 0.6 0.3 0 0]。但是,对我来说,这看起来非常丑陋并且可读性不强。另外,我现在已经手动分配接下来的三个条目应该在 0.4 以下,但我想通过一个变量来管理它,这样我就可以轻松地将逻辑分配给接下来的三十个条目,而不仅仅是三。此外,这创建了正确的向量,但它不会继续 运行 遍历代码并创建新的向量。

根据我对您陈述的要求的理解,您的循环代码给出了错误的结果,即使对于给定的 z 也是如此。 运行 给定 z 的代码,我们得到:

y =
   0.40000   0.20000   0.80000   0.30000   0.60000   0.30000
   0.40000   0.50000   0.60000   0.30000   0.00000   0.00000

但是,至少根据我的理解,第一个 "active interval" 应该是:

   0.40000   0.20000   0.80000   0.30000   0.60000   0.30000   0.30000   0.20000

此处满足三个连续值低于阈值的要求,但您的结果并非如此 y

我不想更正您的 for 循环,并且由于您也要求了一些不同的方法,下面是我的解决方案。如果是 "readable" 或 "ugly",取决于 reader。我试着评论每一行。此外,您可以检查所有中间结果以进一步了解想法和功能。

z = [0.0 0.1 0.4 0.2 0.8 0.3 0.6 0.3 0.3 0.2 0.1 ...
     0.2 0.0 0.3 0.4 0.5 0.6 0.3 0.3 0.2 0.1 0.0]; 

% Threshold
thr = 0.4;

% Successor threshold
nSucc = 3;

% Find indices, where z >= threshold ("overshoot")
idxOver = find(z >= thr);

% Calculate distances between these overshoots
distOver = diff(idxOver);

% Distances below successor threshold are considered to belong 
% to the same active interval; split active intervals where
% successor threshold is exceeded
idxSplitItv = find(distOver > nSucc);

% Determine starts and ends of the active intervals
idxActiveS = idxOver([1, idxSplitItv+1]);
idxActiveE = idxOver([idxSplitItv, numel(idxOver)]) + nSucc;
nActive = numel(idxActiveS);

% If end of last interval would exceed length of z, ignore
if (idxActiveE(end) > numel(z))
  x = 1:nActive-1;
else
  x = 1:nActive;
end

% Get all active intervals
yy = arrayfun(@(x) z(idxActiveS(x):idxActiveE(x)), x.', 'UniformOutput', false)

对于给定的 z,我们得到:

yy =
{
  [1,1] =
     0.40000   0.20000   0.80000   0.30000   0.60000   0.30000   0.30000   0.20000

  [2,1] =
     0.40000   0.50000   0.60000   0.30000   0.30000   0.20000
}

由于 "active intervals" 可以有不同的长度,我决定使用元胞数组作为输出。注意:arrayfun 只是一些伪装的循环,所以最后一步的循环在这里也可以。

如果我们从 z 中删除最后三个元素,这样就没有有效的第二个 "active interval"(低于阈值的连续值少于三个),我们正确地得到:

yy =
{
  [1,1] =
     0.40000   0.20000   0.80000   0.30000   0.60000   0.30000   0.30000   0.20000
}

另一方面,如果我们设置 nSucc = 10,即我们需要至少十个连续的值低于阈值,我们得到:

yy = {}(0x1)

也就是说,因为在给定的z.

中没有这样的区间

希望对您有所帮助!

免责声明:我用 Octave 5.1.0 测试了代码,但我很确定它应该完全与 MATLAB 兼容。如果没有,请发表评论,我会尽力解决可能出现的问题。