Skip to content

Latest commit

 

History

History
202 lines (155 loc) · 7.53 KB

自适应含噪信号过零率算法.md

File metadata and controls

202 lines (155 loc) · 7.53 KB

本文讨论的是实际使用过程中计算过零率的一种自适应方法。过零率常用于语音检测识别中,一般叫短时过零率更贴切些(指一段短时平稳信号才能计算过零率),简单有效,近期亦打算将这个简单的概念用于识别脚步声和卡车声(近似短时平稳)。过零率的定义计算一般通过下面的表达式描述:

过零率是对频率从时域进行的一种简单的度量,一般情况下,过零率越大频率近似越高,反正亦然,相关推倒可参考相关文献。

自适应噪声阈值

自然信号由于电路、环境引入的噪声会在0水平位置波动,直接按上式计算过零率,严重影响识别效果。因此,本文在计算过零率时,对信号的幅值进行阈值限定,阈值的计算方法是:

其中F为阈值与峰峰值的系数因子,一般F在0.1~0.2之间,Vpp表示当前短时信号的峰峰值,THR(t)表示t时段的阈值。

因此增加阈值判别后计算过零率的流程图为:

![过零率流程图]

对应的C程序为:

/* signal thresh adaptive structure */
struct st_zerorate_thr{
    uint32_t pre;
    uint32_t cur;
};

/*
 * @brief   
 *   Calculate short time zero cross rate. Short time means n, n often choose to
 *   be a frame(256,512 and so on)
 *
 *   The diffrence with upstairs is that this one consider the adaptive thresh 
 *   when checking the signal, which removes the influence of noise.
 * @inputs  
 *   x[] - input sound signal
 *   n   - size of a frame
 * @outputs 
 * @retval  
 *   zero cross rate in a frame length
 */
uint16_t zero_rate(int16_t x[], int n, struct st_zerorate_thr thr)
{
    int      i        = 1;   /* Init to 1 */
    uint16_t zero_cnt = 0;
    float    tmp      = 0;
    uint8_t  x_pre    = 0;

    while ( (x[i] < thr.cur) && (x[i] > -thr.cur) && (i<n) ) {
        i++;
    }
    x_pre = x[i++];
    while ((i < n) && ((x[i] > thr.cur) || (x[i] < -thr.cur)) ) {
        tmp   = x[i] * x_pre;
        if (tmp < 0) {
            zero_cnt = zero_cnt + 1;
        }
        x_pre = x[i];
        i++;
    }

	return zero_cnt;
}

上面代码定义了阈值结构体st_zerorate_thr,更新阈值的方法按(2)式执行,

#define TH_FACTOR        (0.2f)   /* 0.1~0.2 */

void zerorate_thr_update(struct st_zerorate_thr thr, uint32_t peak_value)
{ 
    thr.pre = thr.cur;
    thr.cur = (uint32_t)(((thr.pre + TH_FACTOR * peak_value) / 2) );
}

关于初始阈值的选择:

改进:增加能量阈值的策略

这时要考虑的情况有些复杂,除了噪声阈值外,还要考虑能量阈值(确定是否是信号段),如下图:

signal

上图为采集的地震信号(比如脚步声信号),只有有些数据才是我们想要分析的,因此可以通过能量对数据进行划分。为简单起见,直接通过信号的幅值对确定有效信号区域也是可以的。

当大于某个固定的阈值energy_thr时,并持续一段时间时,认为信号进入有效区域,开始按“自适应噪声阈值”的方案进行计算过零率

能量阈值一般都大于自适应噪声阈值,可以通过实验获得:

  1. 采集无信号时的背景噪声,计算峰峰值;

  2. 采集有目标时的信号,计算峰峰值

在两者之间找到一条错误率最低的水平分界值,作为能量阈值。

为简化程序的设计,本程序使用状态机的设计思想,2个状态:安静(无目标)状态、有目标状态。C程序上直接使用switch...case语句就可以了,对应的C程序如下:

/*
 * @brief   
 *   Calculate short time zero cross rate. Short time means n, n often choose to
 *   be a frame(256,512 and so on)
 *
 *   The diffrence with upstairs is that this one consider the adaptive thresh 
 *   when checking the signal, which removes the influence of noise.
 * @inputs  
 *   x[] - input sound signal
 *   n   - size of a frame
 *   thr - threshold(Vp) for removing noise ripple
 *   energy_thr - threshold(Vp) for ensure wether is signal start or stop
 * @outputs 
 * @retval  
 *   zero cross rate in a frame length
 */
uint16_t zero_rate(int16_t x[], uint32_t n, struct st_zerorate_thr thr, uint16_t energy_thr)
{
    uint32_t i          = 0; 
    uint16_t zero_cnt   = 0;
    int16_t  x_pre      = 0;
    uint8_t  status     = 0;
    uint8_t  energy_cnt = 0;

#define CONTINUOUS_BEGIN    (2)  // 持续大于能量阈值的点数,用于检测信号开始
#define CONTINUOUS_END      (5)  // 持续小于能量阈值的点数,用于检测信号结尾

    for (i=0; i<n; i++) {
        switch(status) {
        case 0: // Slience or maybe signal
            if (abs(x[i]) > energy_thr) {
                if (++energy_cnt >= CONTINUOUS_BEGIN) {
                    status = 1;
                    energy_cnt = 0;
                    x_pre = x[i];
                } else {
                    // do nothing
                }
            }
            break;
        case 1: // Signal
            if (abs(x[i]) > thr.cur) {
                if ( (x[i] * x_pre) < 0) {
                    zero_cnt = zero_cnt + 1;
                }
                x_pre = x[i];
                energy_cnt = 0;
            } else {
                if (abs(x[i]) < energy_thr) {
                    if (++energy_cnt >= CONTINUOUS_END) {
                        status = 0;
                        energy_cnt = 0;
                    }
                } else {
                    // do nothing
                }
            }
            break;
        default:
            status = 0;
            break;
        }
    }

	return zero_cnt;
}

补充:测试效果及新方法提出

好吧:结论只有一个:

在含有低频噪声的环境,使用过零率是很难区分脚步声和卡车的。

如下,是分别采集脚步声和卡车的图形:

step

car

因为卡车的采集信号高频都载波到低频信号上了,而在未判断实际目标之前,是无法使用低通滤波进行滤波(可能滤掉脚步声信号)。

综上,我看过很多的论文,大都提到使用过零率对脚步声了卡车进行识别,而且识别效果还不错,我不知他们的实验环境是什么样的,至少从上面的实验分析,还是有问题的。

因此,提出新的特征,用于区分两类信号——数字化占空比。其过程是:设定一个阈值,从头到尾扫描一帧信号,大于阈值的点设为1,否则设为0,我称之为数字化过程,然后计算高电平(即1)占所有一帧(512点)的百分比,用该百分比作为脚步声和卡车的识别数学特征。好了,我们用数学表述得专业些:

其中x>=THR表示序列中值大于THR的点数。测试结果:取THR=0.4*Vpp,则计算脚步信号的Dutycycle=4,而卡车信号的Dutycycle=113,差异非常明显。