1、聊一聊
其实每个人在无助的时候都需要一句cry on my shoulder! 今天跟大家介绍一种波峰波谷的检测方法,不是很难,不过能够凸显数学在编程算法中的重要作用。
2、正文部分
波峰波谷用处
对于信号波峰波谷识别在嵌入式领域应该是非常广泛的,因为大部分的信号都处于一种时变的状态,信号在时域上处于一种类似于正弦波的波动状态。
比如计步软件就是通过imu模块所采集的变化的波形状态来识别波峰波谷,最终估算你所走过步数;
上图显示了一个典型的x-, y-和z-测量模式,对应于一个跑步者的垂直,向前和侧面加速度。无论如何佩戴计步器,至少有一个轴会有相对较大的周期性加速度变化,因此通过检测其波峰波谷等算法即可对于检测步行或跑步的单位周期至关重要。
还有在电力系统中的交流电压电流,我们需要通过检测波峰波谷来确定电压电流在交流周期中的最大最小值,从而动态调节系统参数来达到自适应的目的,所以波峰波谷的检测是非常有用的。
比较法识别
常规的设计办法为比较法 : 其中x表示当前采样点
波峰:f(x) > f(x−1) 且 f(x) > f(x+1)
波谷:f(x) < f(x−1) 且 f(x) < f(x+1)
然而这样识别对于没有什么噪声,且每个采样点为不同的信号来说还是合适的,但在严苛的环境中还需要构造更多的判断条件来进行一些错误判断的规避,终究还是麻烦了一些,并且容易遗漏。
差分识别
在学生阶段我们就学习了导数的概念,如果一个函数一阶导数左右异号,那分别就是波峰或者波谷。而对于数字信号的处理通过采样都会变成离散信号,信号对时间的微分在离散域内即为差分。 在进行波形识别之前数据采集是必不可少的,其中最重要的是采样速率和精度,以便从采样信号中不失真的恢复原连续信号。(香农采样) 采样的过程中由于电子器件的杂讯等,数据难免会引入噪声,为了简化识别算法一般都会进行滤波处理,比如一些平滑处理等,然后才开始波峰波谷识别。
a、识别算法过程
1、获得采样点序列
2、进行差分处理
3、由于不在乎具体的差分幅值,把所有数据归一到-1,0,1
4、差分值为0的点即为相同点,如果使用比较法则峰值检测可能失效,便需要更多的条件,而这里我们直接把相同点0置为前一个非0即可规避该问题。
5、最终diff再次进行差分,-2/+2即为波峰/波谷。
b、参考代码
1#include 2#include 3#define sample_max 20 4#define pv_max 10 5 6float sample[sample_max]={1,2,3,4,4,4,5,2,1,0,0,5,1,0,0,1,2,3,4,0}; 7float samplediff[sample_max]={0}; 8 9typedef struct _tag_findpv 10{ 11 int pos_peak[pv_max]; //波峰位置存储 12 int pos_valley[pv_max]; //波谷位置存储 13 int pcnt; //所识别的波峰计数 14 int vcnt; //所识别的波谷计数 15}sfindpv; 16 17sfindpv stfindpv; 18 19/******************************************** 20 * fuction : initialfindpv 21 * note : 初始化相关数据 22 *******************************************/ 23void initialfindpv(void) 24{ 25 int index = 0; 26 27 for(index = 0; index < sample_max;index ++) 28 { 29 samplediff[index] = 0; 30 } 31 32 for(index = 0; index < pv_max;index ++) 33 { 34 stfindpv.pos_peak[index] = -1; 35 stfindpv.pos_valley[index] = -1; 36 } 37 stfindpv.pcnt = 0; 38 stfindpv.vcnt = 0; 39 40} 41 42/******************************************** 43 * fuction : findpv 44 * note : 找波峰波谷 45 *******************************************/ 46void findpv(sfindpv *pfindpv,float *sample) 47{ 48 int i = 0; 49 50 //step 1 :首先进行前向差分,并归一化 51 for(i= 0; i 0) 54 samplediff[i] = 1; 55 else if (sample[i + 1] - sample[i] = 0) 76 samplediff[i] = 1; 77 else 78 samplediff[i] = -1; 79 } 80 81 } 82 } 83 84 //step 3 :对相邻相等的点进行领边坡度处理 85 for(i= 0; i pos_peak[pfindpv->pcnt] = i + 1; 90 pfindpv->pcnt++; 91 } 92 else if(samplediff[i + 1] - samplediff[i] == 2) //波谷识别 93 { 94 pfindpv->pos_valley[pfindpv->vcnt] = i + 1; 95 pfindpv->vcnt++; 96 } 97 } 98} 99100/********************************************101 * fuction : main102 * note : 模拟查找波峰波谷 103 *******************************************/ 104int main(int argc, char *argv[]) {105106 int i = 0;107108 initialfindpv();109110 findpv(&stfindpv,sample);111112 printf(peak);113 for(i = 0 ;i< stfindpv.pcnt;i++)114 {115 printf(-%d,stfindpv.pos_peak[i] + 1); //加1是为了与上图横坐标一致 116 }117118 printf(valley);119 for(i = 0 ;i< stfindpv.vcnt;i++)120 {121 printf(-%d,stfindpv.pos_valley[i] + 1);122 }123124 printf();125 printf(欢迎关注:最后一个bug);126 return 0;127}
2、最后
当然在实际的项目中为了更加稳定的识别波峰波谷可能会对波峰波谷的出现特点进行限制,从而进一步减少误识别,也有许多人使用数据拟合的办法来识别波峰波谷,那么识别的准确度就与所拟合的函数有关,通过数学方法对所拟合函数进行波峰波谷的求解,最终得到信号的波峰波谷,不过这样的拟合过程对平台的处理能力提出了一定的要求。
远距离物联网控制系统技术,你知道几个?
补贴暂停之后,三元锂电池行业面临夭折?
google glass为何停产_google眼镜为什么失败
手术机器人在国内的发展趋势
Banana Pi BPI-R3 Mini 介绍:一款小巧而强大的嵌入式路由器板
给大家介绍一种信号波峰波谷的检测方法
从本地部署到 AI 赋能,微软揭开产品现代化秘诀
双十二来临,你不可错过的华为最美手机
LED发光手写笔DIY自制
一种具有高度柔性与可塑性的超香肠覆盖式神经元模型
山东移动联合青岛港打造“5G+智慧港口”,推动青岛港自动化码头升级
下变频器输入信号幅度对下变频的影响
Stratix IV内嵌DPA电路的基本结构分析
配电室智能化运维
电机铁芯的作用是什么
MSPM0L1306开发板教程之通用定时器
未来已来,这些开发机遇你要知道
工业级无线路由器的功能优势都有哪些
高通2023财年净利润72.32亿美元下降44%
华为P10怎么样?华为P10评测:国产旗舰华为P10售价良心,却为何遭网友吐槽?