在一维中找到具有某种结构的峰

finding peaks that have some structure in 1-d

我的峰值信号在某些背景之上具有某种结构,我正试图找到一种稳健的方法来定位它们的位置和幅度。

例如,假设峰具有这种形式:

t=linspace(0,10,1e3);
w=0.25;
rw=@(t0) 2/(sqrt(3*w)*pi^0.25)*(1-((t-t0)/w).^2).*exp(-(t-t0).^2/(2*w.^2));

我有几个峰太近了,所以它们的结构开始干扰其他峰,一个分开,所以你可以看到它的结构:

pos=[ 2 2.5 3 8]; % positions
total_signal=0.*t;
for i=1:length(pos) 
   total_signal=total_signal+rw(pos(i));
end
plot(t,total_signal);

所以目标是找到在 total_signal 中找到的所有峰,并检查它们的位置是否与用​​于在 pos 中生成它们的原始位置一致。

您的信号可以被认为是脉冲序列与峰形的卷积。反卷积可用于检索脉冲序列,其峰值就是您要查找的位置。这假设峰形已知且恒定。

我将从如下重写您的代码开始:

t = linspace(0,10,1e3);
w = 0.25;
rw = @(t) 2/(sqrt(3*w)*pi^0.25)*(1-((t)/w).^2).*exp(-(t).^2/(2*w.^2));

pos = [2, 2.5, 3, 8];
total_signal = zeros(size(t));
for i=1:length(pos) 
   total_signal = total_signal + rw(t-pos(i));
end
total_signal = total_signal + randn(size(t))*1e-2;
plot(t,total_signal);

我已经将 rw 改为 t-t0,而不仅仅是 t0。这将使我稍后可以创建一个干净的信号,中间只有一个峰值。我还为信号添加了噪声,以解决更现实的问题。没有噪音,问题就容易解决了。

Wiener deconvolution 是解决这个问题最简单的方法。简而言之,我们假设

total_signal = conv(pulse_train, shape)

在频域中,这写成

G = F .* H

(与 .* 相乘 element-wise,此处使用 MATLAB 语法)。维纳反卷积是:

F = (conj(H) .* G) ./ (abs(H).^2 + k)

使用 k 一些常数,我们可以调整这些常数以正则化解。

我们按如下方式实现:

shape = rw(linspace(-5,5,1e3));
G = fft(total_signal);
H = fft(ifftshift(shape)); % ifftshift moves the origin to sample #0, as expected by FFT.
k = 1;
F = (conj(H) .* G) ./ (abs(H).^2 + k);
pulse_train = ifft(F);

现在,findpeaks(需要信号处理工具箱)可用于查找突出的峰值:

findpeaks(pulse_train, 'MinPeakProminence', 0.02)

注意四个峰的高度大致相同。这并不准确,因为我们正在规范化处理噪音。只有在 noise-free 情况下才可能有精确解。没有噪声,k=0,表达式简化为F = G ./ H.

此外,x-axis 在 findpeaks 生成的图中不存在,但这应该不会影响结果。它返回的位置是数组的索引,这些相同的索引可用于索引 t 并找到峰值的实际位置。