数字信号处理 录制不同发音的三个字,如数字1、2、3,对语音信号做频谱分析,画出采样后的语音信号的时域波形和频域图 分析这三个字的发音频率差异,根据频率不同,区分一个未知发音。 文档,Matlab文件、gui

最近在折腾语音信号分析,发现不同数字的发音在频谱上藏着不少好玩的信息。就拿最简单的1、2、3来说,虽然都是单音节,但它们的频率特征差异明显到可以当密码用。先剧透结论:基频(F0)和共振峰(Formant)是区分它们的关键。

第一步:录个音先

用手机或麦克风录下自己清晰念出的"1"、"2"、"3",保存为.wav文件。Matlab里直接用audioread加载:

[y, fs] = audioread('number1.wav');

采样率fs通常选16kHz就够了,毕竟人声主要能量在8kHz以下。

看波形先别慌

时域波形直接暴露发音的振幅变化。比如"3"的尾音拖得比较长,波形衰减更慢:

t = (0:length(y)-1)/fs;
plot(t, y);
xlabel('时间(s)');
ylabel('振幅');
title('"3"的时域波形');

对比三个数字的波形,会发现"1"的起振更突然,而"2"的振幅包络像个小山包。

频域才是重头戏

数字信号处理 录制不同发音的三个字,如数字1、2、3,对语音信号做频谱分析,画出采样后的语音信号的时域波形和频域图 分析这三个字的发音频率差异,根据频率不同,区分一个未知发音。 文档,Matlab文件、gui

FFT一上场,真相就藏不住了。加个汉明窗防止频谱泄漏:

N = 2^nextpow2(length(y));
Y = fft(y.*hamming(length(y)), N);
f = fs/2*linspace(0,1,N/2+1);
plot(f, 20*log10(abs(Y(1:N/2+1))));
xlabel('频率(Hz)');
ylabel('幅度(dB)');

重点看两个区域:

  1. 基频:男声约80-150Hz,女声约150-300Hz
  2. 第一共振峰:300-1000Hz,决定元音特性

实测发现:"1"的基频集中在250Hz附近,共振峰在800Hz有个尖峰;"2"的基频略低(200Hz),但共振峰在500Hz和1500Hz双峰结构;"3"的基频飘忽不定(可能受尾音影响),但1200Hz附近必有能量堆积。

写个分类器试试

粗暴版规则:用峰值检测锁定主要频率成分:

[pks, locs] = findpeaks(abs(Y(1:N/2+1)), 'MinPeakHeight', max(abs(Y))*0.3);
main_freqs = f(locs(1:2)); % 取前两个显著峰值

判断逻辑:

  • 若main_freqs(1) > 230Hz → 可能是"1"
  • 若main_freqs(2)在400-600Hz → 大概率是"2"
  • 若main_freqs(2) > 1000Hz → 认作"3"

附赠GUI操作指南

懒得写代码?Matlab的App Designer拖个按钮搞定:

  1. 导入音频按钮 → uigetfile
  2. 分析按钮 → 调用上述FFT代码
  3. 结果显示区 → 用uiaxes画频谱+文本判决

完整工程文件(含测试语音)已扔GitHub,需要自取:

github.com/xxx/voicedspdemo (注:链接需替换为实际地址)

避坑提示

  • 环境噪声太大?加个预加重滤波器filter([1 -0.97],1,y)
  • 基频检测翻车?试试pitch(y,fs)函数,比手动找峰值稳
  • 共振峰跟踪玄学?用LPC系数逆推更准,但计算量飙升

最后放个挑衅:拿这个方案去区分"4"和"10",保证翻车——所以啊,特征工程才是真·技术活。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐