检测DTMF信号质量

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了检测DTMF信号质量相关的知识,希望对你有一定的参考价值。

简 介: 利用计算机声卡录制了电话机在没有连线情况下发送DTMF信号,利用Python编程,截取了所有拨码信号,利用FFT分析了其中的DTMF成分,并进行译码。通过实验证明,控制板在没有连线情况下,总共发送了589次电话号码,所有的号码都是正确。但是在发送过程,可以看到对于某些信号会出现间隔。比如下面就是其中一次拨码,在拨码信号中间存在短暂的简短。

关键词 DTMF信号频谱

背景介绍 目 录
Contents
DTFM电话拨号标准 解决工程问题 信号分析 录制信号 读取和显示 有效数据截取 判断数据电话号码 处理所有拨码信号 处理数据 处理完整代码 检测总结

 

§00 景介绍

0.1 DTFM电话拨号标准

  DTMF 指 Dual-tune Multi-Frequency,用于早期电话拨码信号发送。几乎在人们开始使用电报、电话系统传递信息,人们就需要发现一种方式可以机械重复可靠的与系统交互。现在信号系统可以完成这些任务,包括接线、拨号以及与电话系统进行交互。
  最早使用的电话信号系统是脉冲拨号,下面这种转盘式拨号系统利用内部机械系统中断电话连接,产生电信号用于传递电话拨号信息。

▲ 图1 带有拨码转盘的电话机

  第一个双音频电话机是在 1963年11月份由贝尔实验室首次引入使用 ,并迅速取代了旋转拨号电话机。现在所使用的标准为 ITU Q.23推荐标准 .

▲ DTMF信号标准

0.2 解决工程问题

  在电话双音频拨号声音中的干扰信号中对于旧式拨码电话改造项目中,出现的电话拨号出现的偶发错误。现在通过对利用计算机声卡采集到电话拨号声音进行分析,来判断出现的这种偶发错误究竟来自于控制器系统内部,还是来自于和外部电话机连接方面的错误。

  在今天(2022-01-21)录制了大约3个小时的拨号声音,是在没有连接电话线的情况下录制的。这样可以判断内部电话机系统本身在发送信号过程中是否会出现发送些信号故障问题。

录制音频信号:
录制软件:Audacity
录制频谱:44.1kHz
通道数:2(两个通道一样的模拟信号)
时间:大约为3个小时

  信号发送的电话号码为: 18612110728

 

§01 号分析


1.1 录制信号

  录制的信号上载AI Studio,建立了音频数据库。这个数据集合包括了六段利用计算机声卡录制的电话双音频信号。

▲ 图1.1.1 双音频电话报号声音

  包含有信号:

  • 三个离线信号:wav2,sound1,DTFM_RECORD_2022-1-21
  • 两个在线信号:ONLINE-WAVE1;ONLINE-WAVE2

1.2 读取和显示

1.2.1 wav

(1)读取数据

import sys,os,math,time
import matplotlib.pyplot as plt
from numpy import *
from scipy.io import wavfile

filename = '/home/aistudio/data/data126234/wav2.wav'
sample_rate,sig = wavfile.read(filename)
print("sample_rate: \\n".format(sample_rate), "shape(sig): \\n".format(shape(sig)))
sample_rate: 44100
shape(sig): (45646080, 2)
sig.shape[0]/sample_rate: 1035.0585034013604

(2)显示信号波形

plt.clf()
plt.figure(figsize=(10,6))
plt.plot(sig[:,0])
plt.xlabel("n")
plt.ylabel("value")
plt.grid(True)
plt.tight_layout()
plt.savefig('/home/aistudio/stdout.jpg')
plt.show()

▲ 图1.2.1 所有信号的波形

▲ 图1.2.2 截取的第一个拨码信号

(3)显示数据的视频联合分布

  使用Signal Spectrogram函数显示数据的短时傅里叶变换。

▲ 数据的短视傅里叶变换

from scipy import signal

f,t,Sxx = signal.spectrogram(sig[startid:endid, 0], fs=sample_rate, nperseg =2048, noverlap=2000, nfft=8192)

thread = 1500000
Sxx[where(Sxx>thread)] = thread

plt.clf()
plt.figure(figsize=(10,7))
plt.pcolormesh(t, f[50:350], Sxx[50:350,:])
plt.xlabel("Time(S)")
plt.ylabel("Frequency(Hz)")
plt.grid(True)
plt.tight_layout()

plt.savefig('/home/aistudio/stdout.jpg')
plt.show()

1.3 有效数据截取

  为了便于对数据进行判断,需要优先截取下有效数据,然后再判断其中的频谱是否正确。

1.3.1 数据基本参数

(1)相邻两组信号之间的时间间隔

  下图显示了相邻两个拨码信号之间的波形关系。

▲ 相临两个拨码信号

  通过上面波形可以看到,由于进行电话的摘挂机,产生的两个高脉冲信号幅度超过30000, 因此根据这个可以将信号进行有效的分割和定位。

  如下 是一个尖脉冲波形放大后的图像。

▲ 图1.3.2 一个尖脉冲的波形

  可以根据该脉冲波形的前面的上升沿的起始位置来确定该脉冲的位置。

dataseg = list(where(abs(sig[:,0])>0x7f00))
print(dataseg, shape(dataseg))

print(dataseg[:100])

posid = dataseg[0]
posdelta = [s1-s2 for s1,s2 in zip(posid[1:], posid[:-1])]

print(posdelta[:1000])
plt.clf()
plt.figure(figsize=(10,6))
plt.plot(posdelta)
plt.xlabel("n")
plt.ylabel("deltapos")
plt.grid(True)
plt.tight_layout()
plt.savefig('/home/aistudio/stdout.jpg')
plt.show()
[array([  355749,   355750,   355751, ..., 45120329, 45120330, 45120331])]
(1, 25351)
[array([  355749,   355750,   355751, ..., 45120329, 45120330, 45120331])]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 786481, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 785271, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

▲ 图1.3.3 所有上升沿对应的波形

  这些上升脉冲它们之间的间隔为:

pd = array(posdelta)
possplit = pd[where(pd > 1000)]
print("possplit: \\n".format(possplit), "len(possplit): \\n".format(len(possplit)), "mean(possplit): \\n".format(mean(possplit)), "mean(possplit)/sample_rate: \\n".format(mean(possplit)/sample_rate))
possplit: [786481 785271 786005 785485 785631 785996 785302 786970 785405 784943
 786674 784894 785761 785753 786155 784973 786987 783855 784476 783570
 782555 784458 782916 785667 789454 784251 783545 783764 784366 784989
 784486 787431 784040 783745 785528 783743 784939 789109 785727 787110
 783177 783532 786536 783833 784088 783743 783043 783922 782797 784285
 784523 784822 782861 784441 783300 783629 784274]

len(possplit): 57
mean(possplit): 784898.5263157894
mean(possplit)/sample_rate: 17.798152524167563

  从上面结果来看,在wav2file中总共有57个拨码片段,平均它们之间的时间间隔为: T s = 17.8 s T_s = 17.8s Ts=17.8s

1.3.2 截取数据

  截取数据是出指吧拨号11个脉冲的音频数据截取出来。

▲ 图1.3.4 信号波形

  在拨码信号前对应的时间间隔大于400000。

wavefilename = '/home/aistudio/data/data126234/wav2.wav'

sample_rate,sig = wavfile.read(wavefilename)

dataseg = list(where(sig[:,0] > 20000))
posid = dataseg[0]
posdelta = [s1-s2 for s1,s2 in zip(posid[1:], posid[:-1])]

plt.clf()
plt.figure(figsize=(10,6))
plt.plot(posdelta[:9000], label='POSDELTA')
plt.xlabel("n")
plt.ylabel("deltapos")
plt.grid(True)
plt.tight_layout()
plt.savefig('/home/aistudio/stdout.jpg')
plt.show()

▲ 图1.3.5 前两小段数据

  下面给出电话信号起始位置。

beginid = array(list(zip(posid[1:],posid[:-1])))[where(posdelta > 400000)]
print("beginid.T: \\n".format(beginid.T), "shape(beginid): \\n".format(shape(beginid)))
beginid.T: [[  836306  1621745  2408903  3193945  3980233  4765672  5551524  6339190
   7124987  7912553  8698676  9484556 10269399 11054722 11842377 12629740
  13414451 14203456 14986067 15770299 16553373 17339407 18122751 18908758
  19698392 20481857 21268481 22049985 22836030 23620779 24406880 25192396
  25979819 26763351 27549539 28332773 29118796 29908430 30692265 31480796
  32266869 33047810 33835365 34619228 35405796 36189780 36973047 37755785
  38542178 39324767 40108260 40895783 41678995 42463568 43246945 44032197
  44816043 45602380]
 [  356796  1143719  1929410  2715871  3501790  4287880  5074302  5860021
   6647411  7433280  8218650  9005777  9791085 10577298 11363487 12150076
  12935483 13722878 14507173 15292070 16076090 16859083 17643994 18427354
  19213444 20003346 20788030 21572011 22356204 23141016 23926446 24711360
  25499256 26283716 27067917 27853868 28638069 29423430 30212969 30999135
  31786684 32570306 33354257 34141237 34925519 35710046 36494197 37277688
  38062044 38845293 39630016 40414985 41200222 41983539 42768398 43552158
  44336209 45120939]]

shape(beginid): (58, 2)

(1)截取一段数据

wavetime = 2.25
wavelength = int(sample_rate * wavetime)以上是关于检测DTMF信号质量的主要内容,如果未能解决你的问题,请参考以下文章

检测DTMF信号中的时间间隔

使用Goertzel算法识别DTMF信号

MT8870DTMF解码器测试

visual c++已经得到一个信号的波形,怎样检测波峰和波谷?

数字信号基于matlab DTMF电话拨号音识别含Matlab源码 218期

数字信号基于matlab GUI DTMF双音多频信号仿真演示系统(戈泽尔算法)含Matlab源码 016期