ShakyVoice - 语音压力分析工具






4.10/5 (25投票s)
这是为 Pocket PC 实现的一个简单的语音压力分析工具;它可以在旅途中用作测谎仪。
引言
ShakyVoice(最初代号为 BatteryDrainer Pro)是您 Pocket PC 上一款简单的语音压力分析工具。它只测量暴露压力的众多语音参数中的一个,然而,这正是大多数廉价电话对话测谎仪所做的。我只添加了一个时间轴跟踪功能,可以随时间查看数值,而且程序不会说什么是真话,什么是假话——这种处理需要您自己根据一些真话和假话的样本来完成。我认为这使得该程序比那些不知道真话是什么样子的愚蠢玩具更准确、更有用。
如何使用它?
*此程序需要安装 MS .NET Compact Framework。
该应用程序直接测量语音压力。您可以通过比较录制的真话文件和假话文件中的压力差异来测量谎言。形式上,它是这样的
LieMeasure = |TruthFileStressReading - LieFileStressReading|
程序不显示 LieMeasure
,因为您总是需要输入两个文件(真话和假话)。如果您已经对说话者的正常参数有所了解,可以查看单个文件,这样您就可以看到是否存在差异。
您首先录制一个真话文件和一个假话文件。程序仅支持 8khz PCM 单声道文件,因此您需要转到 **开始 -> 程序 -> 设置 -> 输入**,将 **语音录音格式** 设置为 **8,000 Hz, 16 Bit, Mono (16 KB/s)**,并确保您 **没有** 选择任何 GSM 或 Microsoft 格式,该应用程序仅适用于未压缩的 PCM WAVE 文件。否则,它将显示错误消息或错误数据(取决于您做得不对的地方)。现在,要录制真话文件,请转到 **录音 -> 录制真话**,并按正常方式使用控件。然后,您可以通过 **录音 -> 录制假话** 来录制假话文件。录制的任何文件都会存储在内存中,可以在下次会话中调用。之后,您可以分别分析文件,方法是 **录音 -> 分析真话/假话**。分析后,文件参数会显示在时间轴上。您应该进行短时间录制,最多 30 秒,因为分析非常慢(并且会很快耗尽电池)。这也是实用性和精确度如此基础的原因之一。红线表示压力 - 值越高表示压力越大。白线是信号的总功率,黄线是颤抖功率(实际上是功率的平方根,因为速度考虑)。程序计算颤抖功率相对于总语音信号功率的比例,这是压力的一个良好指标。您通常应该查看最大值(在图表的顶部),只需了解最大值(红色)是多少——这是您分析的一个良好起点。时间以毫秒为单位(在时间条上)。
一般来说,将以下情况视为压力
- 白线没有紧跟黄线。
- 红线很高。
为了区分语音和沉默,您应该注意白线不要太低。白线低表示当前段可能是空的(沉默)。压力估计是基于约 0.5 秒的块,并与一些硬编码因子重叠。
我们为什么要撒谎?
即将推出……是的,没错;)
谎言理论
人们在说谎时会感到压力。谎言越大,压力越大。当他们有可能被抓到或知道自己撒了重要的谎时,他们会感到更大的压力。压力很容易被检测到。任何偏离正常参数的行为都可能表明压力,例如心律、视网膜反应、眨眼频率(这个真的有效)、血压、体温、脑电图图和声音。其他因素更主观,我根本不提它们。在本文中,我将专注于指示压力的语音参数。这是一个非常广泛的话题——有很多方法可以检测有压力的语音,有些方法非常复杂。我实现了一种最简单的方法——一个“糟糕的”微颤抖探测器。它的工作原理是:它估计语音与 8-12 Hz 频率的正弦波的调制。换句话说,它检查语音能量是否在 1/14 - 1/8 秒的时间间隔内跳跃。我们如何做到这一点?——有很多方法——然而,最常见的方法似乎是利用语音数据帧的频谱分析。频谱分析通常是通过使用快速傅里叶变换 (FFT) 算法来获得语音数据的傅里叶变换图像。实现这个算法并不容易——我的是从 Stephan Bernsee 那里获得的。我只需要将一些函数从 C 移植到 C#(将其保留在 unsafe
部分)。如果此时有 DSP 专家在阅读,他/她肯定在笑,因为这不是测量我们所寻找的调制的正确方法。是的,但实际上,如果我们得到 6-15 Hz 频带的能量,我们基本上就得到了正确的调制能量。当然,这不是很精确,但我认为它仍然有用,因为有些人实际上在销售此类设备。
代码审查
最重要的一部分是分析代码。它首先获取一个大小为 FrameSize
的数据块,然后执行 FFT,计算总能量和颤抖能量,并建立压力估算。关于我如何读取/录制波形文件以及如何显示数据,有很多细节,我无法真正评论所有内容。这一切都是工作的成果,没什么特别了不起的。
while(notdone)
{
this.LieFile.inStream.Position=store_pos;
int read=this.LieFile.inStream.Read(tmp,0,FrameSize*2);
if(read!=FrameSize*2)
{
notdone=false;
for(int q=read;q<FrameSize*2;q++) tmp[q]=0;
}
unsafe
{
fixed(byte *pdata=tmp)
{
byte *assignable=pdata;
for(int q=0;q<2*FrameSize;q+=2)
{
short tword=(short)((((int)assignable[1])<<8)|assignable[0]);
fdata[q]=((float)tword)/((float)(0xffff>>1));
fdata[q+1]=0;
assignable+=2;
}
}
fixed(float * fftme=fdata)
{
smbFft(fftme,4096,-1);
}
float total=0;float tremor=0;
for(int q=0;q<FrameSize;q++)
{
fdata[q]=(float)Math.Sqrt(Math.Pow(fdata[2*q],2)+
Math.Pow(fdata[2*q+1],2));
total+=fdata[q];
}
total/=FrameSize;
for(int q=7;q<=15;q++)
{
tremor+=fdata[q];
}
tremor/=6;
Data[1,0].Add(tremor);
Data[1,1].Add(total);
Data[1,2].Add(tremor/total);
}
store_pos+=OverlapFactor;
progressBar1.Value=
(int)(100F*(float)store_pos/(float)this.LieFile.inStream.Length);
}
未来可以做什么?
我将提到一些更高级的技术。一个更准确的压力指标是说话者的音高抖动(或基频)。您是否注意到(在撒谎时)您的声音变得细而高。嗯,那是因为您的音高升高了——我提到的算法在音高变化方面的灵敏度可能是您耳朵和大脑的 100 倍。这将极大地提高准确性。
另一个选择是测量呼吸间隔和语速——这个也非常准确。
所有这三种方法都可以在 Pocket PC 设备上实现,几乎没有硬件/性能要求。
使用的资源
- 非常感谢 Stephan Bernsee 提供的 FFT 例程。
- Brenner, M., Branscomb, H., & Schwartz, G.E. (1979). Psychological stress evaluator: Two tests of a vocal measure. Psychophysiology, 16(4), 351-357.
- comp.dsp。
- 许多互联网网站帮助我验证了该方法。