2. 语音信号的短时傅里叶变换

任务目标

对一段真实语音信号执行短时傅里叶变换(STFT),生成语谱图,并观察元音、清辅音等不同音素的时频特征差异。本案例使用Python实现完整处理链路:读取音频 → 分帧加窗 → FFT → 语谱图可视化。

环境依赖

  • Python 3.8+
  • numpy、matplotlib、scipy、soundfile(用于读取音频文件)

安装命令:pip install numpy matplotlib scipy soundfile

核心实现

以下代码实现STFT及语谱图绘制。音频文件需包含清晰的元音(如/a/、/i/)和清辅音(如/s/、/sh/)片段,建议采样率16kHz,时长2~3秒。

```python import numpy as np import matplotlib.pyplot as plt import soundfile as sf from scipy.signal import get_window def stft(x, win_len=400, hop_len=160, nfft=512, win_type='hann'): """ 短时傅里叶变换 参数: x: 一维语音信号 win_len: 窗长(采样点), 400点@16kHz = 25ms hop_len: 帧移, 160点 = 10ms nfft: FFT点数, 512 win_type: 窗函数类型 返回: spec: 复数谱, shape (nfft//2+1, num_frames) freqs: 频率轴 (Hz) times: 时间轴 (s) """ if x.ndim > 1: x = x[:, 0] # 取单声道 # 补零使总帧数为整数 pad_len = hop_len - (len(x) - win_len) % hop_len if pad_len < hop_len: x = np.pad(x, (0, pad_len)) win = get_window(win_type, win_len) num_frames = (len(x) - win_len) // hop_len + 1 spec = np.zeros((nfft // 2 + 1, num_frames), dtype=np.complex64) for i in range(num_frames): start = i * hop_len frame = x[start:start + win_len] * win spec[:, i] = np.fft.rfft(frame, nfft) freqs = np.fft.rfftfreq(nfft, 1 / 16000) times = np.arange(num_frames) * hop_len / 16000 return spec, freqs, times # ---------- 主流程 ---------- audio_path = "speech_sample.wav" # 替换为实际音频文件路径 x, sr = sf.read(audio_path) assert sr == 16000, f"请将音频重采样至16kHz, 当前采样率: {sr}" spec, freqs, times = stft(x) log_spec = 20 * np.log10(np.abs(spec) + 1e-8) # 转dB刻度 # 绘制语谱图 plt.figure(figsize=(12, 6)) plt.imshow(log_spec, aspect='auto', origin='lower', extent=[times[0], times[-1], freqs[0], freqs[-1]], cmap='magma', vmin=-80, vmax=0) plt.colorbar(label='幅度 (dB)') plt.xlabel('时间 (s)') plt.ylabel('频率 (Hz)') plt.title('语音信号语谱图 (STFT, 窗长25ms, 帧移10ms)') plt.tight_layout() plt.savefig('spectrogram.png', dpi=150) plt.show() ```

运行与验证

  1. 准备音频:录制或下载一段包含连续语音的wav文件(16kHz单声道),命名为speech_sample.wav,置于脚本同目录。
  2. 运行脚本:python stft_demo.py,程序输出spectrogram.png并弹出图形窗口。
  3. 判定通过标准:
  • 语谱图中能观察到明显的横条纹(谐波结构),对应元音段;
  • 清辅音段(如/s/)表现为高频区域(4kHz以上)的均匀亮带,无明显谐波条纹;
  • 浊辅音与元音过渡处可见共振峰(低频暗色横带)的连续变化。

预期输出特征

以一段包含“sa-shi-su”的语音为例,语谱图应呈现:约0~0.3s的/s/段为高频噪声带;0.3~0.6s的/a/段在500Hz、1200Hz、2500Hz附近出现三条明显共振峰横带;0.6~0.9s的/sh/段能量集中在3~6kHz;0.9~1.2s的/i/段第一共振峰降至约300Hz,第二共振峰升至约2200Hz。此描述为基于语音学知识的预期模式,实际图形随说话人及录音环境变化。

常见问题

  • 图形全黑或过暗:检查vmin/vmax范围,可改为vmin=-100, vmax=-20重新映射动态范围。
  • 时间分辨率不足:若辅音爆破段过短,可减小窗长至200点(12.5ms),但频率分辨率会下降。
  • 采样率不匹配:代码硬编码16kHz,若音频为其他采样率,需先重采样或修改freqs计算中的16000为实际采样率。