ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【数字信号处理含matlab代码】第十二篇:智能峰值/谷值检测算法详解

【数字信号处理含matlab代码】第十二篇:智能峰值/谷值检测算法详解 第十二篇智能峰值/谷值检测算法详解在前几篇中我们专注于语音信号的预处理和预测延拓但实际应用中我们常需要从波形中自动定位极值点——例如基音周期中寻找波峰、频谱中识别谐波峰值、或心跳信号中检测 R 波峰值。MATLAB 自带的 findpeaks 函数需 Signal Processing Toolbox功能强大但有时我们需要更轻量、更可控的实现。findpeakm.m 提供了完全自包含的峰值/谷值检测算法支持二次插值亚样本精度、宽度容差去重并且无需任何工具箱依赖。本篇将深入剖析其核心算法从一阶差分定位到插值优化再到局部峰值去重带你全面掌握这个实用工具。峰值检测的核心思想峰值检测的本质是在离散序列中找到局部极大值点。一个点 x(k)是峰值当且仅当其左侧相邻点小于或等于它且右侧相邻点也小于或等于它对于严格的峰值两侧严格小于。但实际信号常伴有噪声直接比较容易出现虚假极值。基本流程计算相邻点的差分一阶导数近似找出差分由正变负的位置 —— 这些位置就是峰值候选点若信号包含谷值则可将信号取反后再执行上述流程可选对候选点进行二次插值获得亚样本级精度的位置和幅值可选根据距离容差剔除相距太近的峰值保留幅值较大者。findpeakm.m 完整实现了上述逻辑并支持 ‘q’ 插值模式和 ‘v’ 谷值模式。代码结构总览function[k,v]findpeakm(x,m,w)% 输入x - 信号向量% m - 模式字符串q 表示二次插值v 表示寻找谷值% w - 宽度容差样本数若两个峰值距离 ≤ w则剔除较低的% 输出k - 峰值位置若 q 模式则为浮点数% v - 峰值幅值主要步骤· 将信号转为列向量若为谷值模式则取反· 计算差分 dx x(2:end) - x(1:end-1)· 找到上升段和下降段的索引dx0 为上升dx0 为下降· 利用上升/下降段的起始和结束位置确定峰值所在位置处理平坦区· 若为 ‘q’ 模式用二次插值修正位置和幅值· 若指定了 w则进行邻近峰值去重· 若为谷值模式将幅值取反回来· 若无输出参数则自动绘图。差分法定位峰值——核心算法详解3.1 计算差分并标记上升/下降dxx(2:end)-x(1:end-1);rfind(dx0);% 上升段的起始索引指向上方点的索引ffind(dx0);% 下降段的起始索引dx(i) x(i1) - x(i)。若 dx(i) 0说明从 i 到 i1 是上升趋势若 dx(i) 0则为下降。3.2 计算相对于上升和下降的“时间距离”这段代码是 findpeakm 的精髓它通过累计“自上次上升/下降以来的样本数”来定位峰值。drr;dr(2:end)r(2:end)-r(1:end-1);rcrepmat(1,nx,1);rc(r1)1-dr;rc(1)0;rscumsum(rc);% rs 向量每个样本点距离最近一次上升点的样本数类似地fs 计算距离最近一次下降点的样本数。3.3 确定峰值候选位置峰值应满足· 它离最近一次上升点很近rs fs说明这个点正处于上升之后· 它离最近一次下降点也很近fq rq说明它即将转为下降· 并且 floor((fq - rs)/2) 0这个条件确保了峰值位于平坦区的中心若存在平坦段。kfind((rsfs)(fqrq)(floor((fq-rs)/2)0));vx(k);在没有平坦区时fq - rs 通常为 1此时 floor(0.5)0满足条件。如果出现一个平台plateau例如 [1, 2, 2, 1]该条件会将峰值定位在平台的中心位置第 2 或第 3 个点取决于 floor 的行为。二次插值 —— 实现亚样本精度当信号峰值不是恰好落在采样点上时我们可以用抛物线拟合三个相邻点左、候选、右来精确估计峰值的真实位置和幅值。设候选点索引为 k其幅值为 x_k左右点为 x_{k-1}和 x_{k1}。构造二次多项式f(t) a t^2 b t c令 t0对应候选点 k则· f(0) c x_k· f(-1) a - b c x_{k-1}· f(1) a b c x_{k1}解得a \frac{x_{k-1} x_{k1}}{2} - x_kb \frac{x_{k1} - x_{k-1}}{2}极值点位置相对于候选点为 t_{\max} -\frac{b}{2a}对应的幅值为f(t_{\max}) x_k - \frac{b^2}{4a}当 a 0时抛物线开口向上那是极小值但峰值处应为 a 0开口向下。若 a \approx 0说明为平坦区则取中心。代码实现ifany(mq)b0.5*(x(k1)-x(k-1));ax(k)-b-x(k-1);j(a0);% 通常 a0此处 j 用于区分平坦区v(j)x(k(j))0.25*b(j).^2./a(j);k(j)k(j)0.5*b(j)./a(j);k(~j)k(~j)(fq(k(~j))-rs(k(~j)))/2;% 平坦区取中心end注意这里 a 0 是异常情况极小值但实际峰值处 a 应为负。代码用 a 判断是否为平坦区a 接近 0如果 a0 则强制按极小值修正但通常不会发生。更稳健的实现应检查 a -eps 才进行插值。邻近峰值去重宽度容差 w当两个峰值之间的距离小于等于 w 时我们只保留幅值较大的那个。这是一个非极大值抑制NMS过程。ifnargin2jfind(k(2:end)-k(1:end-1)w);whileany(j)jj(v(j)v(j1));% 若前一个更高则删除后一个否则删除前一个k(j)[];v(j)[];jfind(k(2:end)-k(1:end-1)w);endend这段代码非常巧妙j 是相邻峰值距离不足 w 的位置索引然后根据幅值比较决定删除前一个还是后一个j 指向较低者。循环直至所有距离均大于 w。谷值检测模式若 m 中包含 ‘v’则函数先将信号取反x -x执行完上述峰值检测后再将幅值取反回来v -v。这样谷值就变成了峰值复用了同一套逻辑。实战示例检测正弦波中的峰值t0:0.01:1;xsin(2*pi*5*t)0.1*randn(size(t));[k,v]findpeakm(x,q,0.1);% 二次插值去重宽度 0.1 样本% 绘制结果findpeakm(x,q,0.1);% 无输出时自动绘图你会看到峰值位置被精确标记且幅值接近 1。二次插值使得位置误差远小于采样间隔。与其他函数的关系· 在语音分析中峰值检测可用于基音周期提取检测相邻波峰距离。· 在频谱分析中检测谐波峰值可进行共振峰估计。· 与 findSegment 结合可在每个有效语音段内单独检测峰值避免静音段的伪峰。本讲小结· 我们深入剖析了 findpeakm.m 的核心算法差分定位、二次插值、邻近去重。· 理解了谷值模式、平坦区处理、亚样本精度等高级特性。· 通过示例展示了其简单易用的接口和强大的绘图功能。峰值检测是信号分析中极为常见的基础操作掌握这个工具将使你在处理各种波形特征提取时游刃有余。下一篇我们将从峰值检测回到语音端点分割学习如何将帧级 VAD 标记转换为连续的语音段结构体。 所有代码均已打包点击下方链接免费获取下载链接下篇预告语音端点检测后处理——连续有话段分割。我们将进入 findSegment.m了解如何将离散的 0/1 标签聚合成有意义的语音片段并计算每个片段的时长为后续的语音识别或特征提取准备结构化数据。敬请期待思考题如果信号中有一个很宽的平坦峰值如方波的顶部findpeakm 会定位在平台中心。若你想要检测平台两侧的边缘应如何修改算法欢迎评论区讨论。
返回列表