Goertzel算法

Goertzel算法由Gerald Goertzel在1958年提出,用于数字信号处理,是属于离散傅里叶变换的范畴,目的是从给定的采样中求出某一特定频率信号的能量,用于有效性的评价。

这个算法有几个关键的参数:

  • 采样率R,指的是需要分析的数据每秒钟有多少个采样
  • 目标频率f,指的是需要检测并评价的这个频率的值
  • 检测区段采样值数量N,也就是每N个采样这个算法会对频率f给出评价
  • 检测区段包含目标频率的完整周期个数K

很显然,上述参数应该有这样的关系:

这个K值应该是一个整数,而且要大小合适。如果太大,不利于检测的时效,如果太小,则检测可能不准确。例如十几甚至二十几左右应该相对合理。例如R为8000,需要检测800hz的频率,N取值100,那么K为10,很不错。但是,需要检测的频率有时候并不那么整,例如697,那么N应该取值多少呢?N在1000以内,无法得到一个整数K,我们只能退而求其次,找一个四舍五入误差最小的。例如N取115,K的计算结果为10.019375,四舍五入为10,而且有较小的误差。

有了上述的参数,然后我们来计算每个采样在一个目标频率一个周期中所占的弧度ω。既然N个采样表达了K个周期(2π),那么ω应该这样计算:

这里需要注意的是,因为K值可能经过了四舍五入,所以上述两个公式必须先后计算,一定不能合在一起化简把K约掉!

然后,我们可以得到后期计算会频繁遇到的系数C:

以上参数,我们都可以事先计算好,不必在每个采样分析中再次计算。之后,就开始针对N个采样进行分析计算

首先初始化:

然后按照顺序针对N个采样每一个值S(我认为这个S一般是一个16位的整数,取值范围在-32768到32767之间,如果你得到的是已经进行过编码的媒体流,例如G.711编码,那么需要首先解码。当然也许采样值就是-128到127之间的单字节整数,那么这样对计算结果中的P值会影响巨大,DTMF识别的时候一些判断参数可能要调整),做如下计算:

上述计算完成之后,我们就可以得到在这N个采样中所体现的频率f的能量值P:

DTMF识别

以上是goertzel算法的全部思想。如果我们要将其用于DTMF识别,还需要做一些工作。DTMF识别,我们需要根据给定的一段时间的采样,能够最大限度地排除噪音的干扰,将有效的DTMF信号识别出来

我们知道DTMF有8个频率:697, 770, 852, 941, 1209, 1336, 1477, 1633,通过前4个频率和后4个频率的两两组合,确定16个符号。那么我们在对给定一段时间的采样进行处理的时候,就需要先将其分为每段为N个采样的多个采样区段,然后对每一区段针对8个频率分别运用goertzel算法进行计算得到每个频率的能量P

为了完成这些能量的计算,我们需要在开始针对8个不同的频率分别计算系数C,而参数N的选择非常关键,因为8个频率的K值都不同,我们要尽可能使得8个频率的K值四舍五入之后都误差尽可能小,经过检验,在采样率为8000的时候,N=205应该是一个最佳值,你可以做一个测试:

N=

function computeK()
{
var n = parseInt(document.getElementById("N").value);
var htmlStr = "

";
htmlStr += "

"
var f = [697, 770, 852, 941, 1209, 1336, 1477, 1633];
for(var i = 0; i ";
htmlStr += "

";
var K = n * f[i] / 8000.0;
htmlStr += "

";
htmlStr += "

";
htmlStr += "

";
htmlStr += "

";
}
htmlStr += "

f K实际值 K近似值 误差
" + f[i] + " " + K + " " + Math.round(K) + " " + Math.abs((Math.round(K) - K)) + "

";
document.getElementById("kTable").innerHTML = htmlStr;
}
computeK()

针对N个采样值,对8个频率分别计算出了能量P之后,我们就可以开始评估这些能量值是否足以表明这N个采样中含有某个DTMF符号

DTMF符号和频率的对应关系如下:

f 1209 1336 1477 1633
679 1 2 3 A
770 4 5 6 B
852 7 8 9 C
941 * 0 # D

我们从1209, 1336, 1477和1633四个频率对应的能量P中取最大值,记作Px,从679,770,852和941四个频率对应的能量P中取出最大值Py。那么Px和Py对应的频率组合极有可能代表识别出一个DTMF符号。但是,我们还需要做一系列的判断,来进一步评估:

  1. Px和Py是否足够强大?我们可以设定一个门限,如果么Px和Py这两个任何一个低于这个门限,那么N个采样被评估为没有识别出DTMF符号。参考资料[2]中建议这个门限值为4*105。但是如果采样值的取值范围是-32768到32767的话,实际上计算出来的P值会非常大,这个门限设为4*109都可以。
  2. Px和Py的差别是否太大?正常的DTMF信号,这两个能量应该接近,那么如果差别较大,我们视为无效。参考资料[2]中建议的方法为:如果Py < Px * 0.398,那么认为无效。如果Px < Py * 0.158也认为无效。但是实际上,我们将0.158改为0.5,识别效果更佳。
  3. 其它频率的能量P有没有很多接近Px和Py的?参考资料[2]中建议的方法为:首先取近Px和Py中较大的那个,设为Pm,如果其他频率的P值有2个以上达到了Pm的15.8%,那么认为是噪音导致,视为无效。

如果上述三个检验关卡都通过了,那么我们可以将这N个采样评估为包含一个DTMF符号,即Px和Py对应的频率组合对应的某个符号。

参考资料:

[1] https://en.wikipedia.org/wiki/Goertzel_algorithm

[2] https://en.wikipedia.org/w/index.php?title=Goertzel_algorithm&oldid=17802166

使用Goertzel算法识别DTMF信号的更多相关文章

  1. 运用kNN算法识别潜在续费商家

    背景与目标 Youzan 是一家SAAS公司,服务于数百万商家,帮助互联网时代的生意人私有化顾客资产.拓展互联网客群.提高经营效率.现在,该公司希望能够从商家的交易数据中,挖掘出有强烈续费倾向的商家, ...

  2. FreeSWITCH收到重复的DTMF信号

    一.背景 用户是运营商手机,拨打的是运营商的固话号码进入的FreeSWITCH的IVR,进入IVR语音播报后,按指定的分机号呼相关人员. 二.现象 用户反映拨打124870找不到指定人员,以前是正常的 ...

  3. IDAPython实战项目——DES算法识别

    在CTF的逆向中我们需要的是找到加密的主函数,结合了yara的识别原理,通过对常量数组的引用的查找,一步步递归构建调用树.调用树根部就是可能的密码算法主函数. 由于这种办法需要常量分布于算法的各个步骤 ...

  4. 机器学习--kNN算法识别手写字母

    本文主要是用kNN算法对字母图片进行特征提取,分类识别.内容如下: kNN算法及相关Python模块介绍 对字母图片进行特征提取 kNN算法实现 kNN算法分析 一.kNN算法介绍 K近邻(kNN,k ...

  5. 深入学习使用ocr算法识别图片中文字的方法

    公司有个需求,简单点说需要从一张图片中识别出中文,通过python来实现,当然其他程序也行,只要能实现,而小编主要学习python,所以就提了python.一个小白在网上遨游了一天,终于找到一丝丝思绪 ...

  6. 算法 识别有效ip地址和掩码并做统计

    题目描述 请解析IP地址和对应的掩码,进行分类识别.要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类. 所有的IP地址划分为 A,B,C,D,E五类 A类地址1.0.0.0~126.2 ...

  7. KNN (K近邻算法) - 识别手写数字

    KNN项目实战——手写数字识别 1. 介绍 k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法.它的工作原理是:存在一个 ...

  8. Amazon验证码机器算法识别

    Amazon验证码识别 在破解Amazon的验证码的时候,利用机器学习得到验证码破解精度超过70%,主要是训练样本不够,如果在足够的样本下达到90%是非常有可能的. update后,样本数为2800多 ...

  9. KNN算法识别手写数字

    需求: 利用一个手写数字“先验数据”集,使用knn算法来实现对手写数字的自动识别: 先验数据(训练数据)集: ♦数据维度比较大,样本数比较多. ♦ 数据集包括数字0-9的手写体. ♦每个数字大约有20 ...

随机推荐

  1. C——第一阶段结束

    C primier 刚好是八月末了,原计划到月中结束的.由于工作上的许多事,忙着学习,测试等.C primier与这周末彻底结束了.加上之前的基础,算是把C又全部重新学习了一遍. 在Linux环境下, ...

  2. [转载]Java程序员使用的20几个大数据工具

    最近我问了很多Java开发人员关于最近12个月内他们使用的是什么大数据工具. 这是一个系列,主题为: 语言web框架应用服务器SQL数据访问工具SQL数据库大数据构建工具云提供商今天我们就要说说大数据 ...

  3. 通过JS简单实现图片缩放

    ;display: none;cursor: pointer;} #FullScreenDiv{;display: none;background-color: #919191;filter: alp ...

  4. Java判断Class变量是什么类型

    public static void main(String[] args) { java.util.Date date_u = new java.util.Date(1); java.sql.Dat ...

  5. oracle 邮件发送

    CREATE OR REPLACE PROCEDURE PRC_sendmail(p_receiver VARCHAR2, -- 邮件接收人                               ...

  6. c++学习一:指针基础

    1.指针优势,当数据量比较大时,通过指针直接访问数据量所在内存.处理更 加复杂的数据结构.例如:链表.二叉树.图等.2.指针本质是一种表示内存地址的数据类型,它和整型int和浮点数float一样 只是 ...

  7. 慕课网-Java入门第一季-6-7 使用 Arrays 类操作 Java 中的数组

    来源:http://www.imooc.com/code/1556 Arrays 类是 Java 中提供的一个工具类,在 java.util 包中.该类中包含了一些方法用来直接操作数组,比如可直接实现 ...

  8. LoadRunner测试结果分析02 转载至zhangzhe的新浪博客

    LoadRunner测试结果分析之我见 上述测试过程的重点在于事务,而LoadRunner生成的测试结果图并不局限于事务上,其中还有是关于Vusers.Errors.Web Resources.Web ...

  9. 学习的目的:理解<转>

    http://www.hkuspacechina.com/chs/news-and-events/news/detail/news-first-day-of-school-2015-04-23 学习的 ...

  10. C中的qsort函数和C++中的sort函数的理解与使用

    一.qsort()函数 原型:_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*)); ...