Java实现波峰统计

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jjwwwww/article/details/82802436

如何统计一段离散信号中波峰的个数呢?来看下面一段波形:

可以非常容易数出波峰的个数3,我们都知道波峰是一段波中的局部最高点,那么此时我们只要找到这样一个点满足:

High(x1)>High(x1-1)

High(x1)>High(x1+1)

即此时x1的值大于其左右两边的值,就可以确定一个波峰了。代码实现一下:

public static int getPeakNum1(float[] data){
        int peak=0;
        
        for (int i=0;i<data.length-1;i++){
            if (data[i]>data[i-1]&&data[i]>data[i+1]){
                peak++;
                i++;
            }
        }
        
        return peak;
}

看起来好像没问题,接着看下面这两幅图:

这两张图看似扭曲,实际上也是一个波峰,但是用上面说的方法便行不通了。

对于此类情况的数据,我们首先要进行筛选,一段连续相等的数据,只需保留一个数据,其余都滤掉即可。看代码:

public static int getPeakNum2(float[] data){
        int peak=0;
        
        //需要三个不同的值进行比较,取lo,mid,hi分别为三值
        for (int lo=0,mid=1,hi=2;hi<data.length;hi++){
            //先令data[lo]不等于data[mid]
            while (mid<data.length&&data[mid]==data[lo]){
                mid++;
            }
            
            hi=mid+1;
            
            //令data[hi]不等于data[mid]
            while (hi<data.length&&data[hi]==data[mid]){
                hi++;
            }
            
            if (hi>=data.length){
                break;
            }
            
            //检测是否为峰值 
            if (data[mid]>data[lo]&&data[mid]>data[hi]){
                peak++;
            }
            
            lo=mid;
            mid=hi;
        }
        
        return peak;
}

—————————————————————————————————————————————————————————

文章到这儿其实可以结束了,但是在实际运用中还会有各种情况,就比如我遇到的这种:

可以看到有两个波峰,但是从整体看其实只有一个波峰,多出来的波峰我称其为伪峰。这个时候可以利用平滑滤波器来对波形进行平滑,但是却不能完全保证能够把多余的伪峰值滤除。因此需要设计一种算法来辅助。由于实际应用中会有千奇百怪的波形,我这里只是针对我自己的情况设计的算法,可以作为一种借鉴。

我们知道,两个波峰之间必然有一个波谷,而两个波谷之间也必然有一个波峰,如:

波峰/波谷/波峰/波谷/波峰/。。。

结合这个规律提供我的算法思路:

(1)先找到所有波峰和波谷

(2)对信号求均值

(3)滤掉所有大于均值的波谷和小于均值的波峰

(4)合并剩下的波峰波谷中相邻的波峰,相邻的波谷,使其满足波峰/波谷的规律

(5)统计剩下的波峰

来看看代码:

public static int getPeakNum3(float[] data){
        int peak=0;

        float[] PeakAndTrough=new float[data.length];

        //需要三个不同的值进行比较,取lo,mid,hi分别为三值
        for (int lo=0,mid=1,hi=2;hi<data.length;hi++){
            //先令data[lo]不等于data[mid]
            while (mid<data.length&&data[mid]==data[lo]){
                mid++;
            }

            hi=mid+1;

            //令data[hi]不等于data[mid]
            while (hi<data.length&&data[hi]==data[mid]){
                hi++;
            }

            if (hi>=data.length){
                break;
            }

            //检测是否为峰值
            if (data[mid]>data[lo]&&data[mid]>data[hi]){
                PeakAndTrough[mid]=1;       //1代表波峰
            }else if(data[mid]<data[lo]&&data[mid]<data[hi]){
                PeakAndTrough[mid]=-1;      //-1代表波谷
            }

            lo=mid;
            mid=hi;
        }

        //计算均值
        float ave=0;
        for (int i=0;i<data.length;i++){
            ave+=data[i];
        }
        ave/=data.length;

        //排除大于均值的波谷和小于均值的波峰
        for (int i=0;i<PeakAndTrough.length;i++){
            if ((PeakAndTrough[i]>0&&data[i]<ave)||(PeakAndTrough[i]<0&&data[i]>ave)){
                PeakAndTrough[i]=0;
            }
        }

        //统计波峰数量
        for (int i=0;i<PeakAndTrough.length;){
            while (i<PeakAndTrough.length&&PeakAndTrough[i]<=0){
                i++;
            }

            if (i>=PeakAndTrough.length){
                break;
            }

            peak++;

            while (i<PeakAndTrough.length&&PeakAndTrough[i]>=0){
                i++;
            }
        }

        return peak;
    }

 

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试