ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Praat中文手册:语音信号处理脚本编写与批量声学分析实战

Praat中文手册:语音信号处理脚本编写与批量声学分析实战

简介:这份 praat 中文学习手册面向语音学研究者、语言学与心理学专业学生及对语音科学感兴趣的初学者,帮助读者系统掌握 praat 在语音信号分析、处理与展示方面的操作。手册围绕软件基本界面、语音文件导入导出、波形与频谱分析、声调韵律研究、元音辅音测量、语音合成、脚本编程及教学演示等模块展开,通过实例与步骤降低上手门槛。资源包为 rar 格式,共 214 个文件,全部为 html 网页文档,整体约 281KB,内容涵盖对象类型、脚本编辑器、公式函数、查询操作等主题页面,便于按目录逐节查阅。目前已有 920 人学习下载,适合希望从零建立语音分析流程、并在实践中查阅具体功能用法的读者参考。

1. 一份被语音实验室翻烂的 Praat 中文手册,到底解决了什么痛点

做语音信号处理的人,几乎绕不开 Praat。它免费、跨平台、脚本能力强,从基频提取到共振峰分析、从标注对齐到批量声学参数导出,都能扛。但真正上手时,很多人卡在同一个地方:官方文档全英文,术语密度高,函数说明写得像天书,遇到一个报错翻半天论坛也找不到中文解释。这份 Praat 中文学习手册,就是冲着这个缺口来的。它把 Praat 的核心操作、脚本语法、常用声学分析流程整理成中文,覆盖从打开音频到批量导出数据的完整链路。适合谁?语音学方向的研究生、做声纹特征的算法工程师、需要批量处理录音数据的社科研究者,以及任何被英文手册劝退过的从业者。它不是简单的界面翻译,而是把「怎么用 Praat 做出一份能写进论文或喂给模型的声学数据」这件事讲透了。

2. Praat 脚本核心语法与对象模型:先搞懂它怎么想问题

2.1 Praat 的对象-命令范式

Praat 的脚本逻辑跟 Python 那种「变量+函数」的写法不太一样。它的核心是「对象(Object)」和「命令(Command)」:你先创建或读取一个对象(比如 Sound、TextGrid、Pitch),然后对这个对象施加命令。每个对象有类型,每个命令只对特定类型生效。理解这一点,后面写脚本才不会出现「为什么这行报错说对象类型不对」的困惑。

常见做法是:打开音频 → 创建 Sound 对象 → 对它做 To Pitch、To Spectrogram 等操作 → 把结果存成 Pitch 对象或 Matrix → 再导出数据。整个过程像流水线,对象在流水线上被不断转换。

手册里把常用对象类型和对应命令列成表,我整理成下面这个速查版:

对象类型典型来源常用命令输出形式
Sound读取 wav / 录音To Pitch、To Intensity、To SpectrogramPitch / Intensity / Spectrogram
PitchSound 转换Get value at time、To PointProcess数值 / PointProcess
TextGrid手动标注或脚本生成Get label of interval、Set interval text标注文本
FormantSound 转换Get formant、Get bandwidth共振峰数值
Table脚本创建或从文件读Append row、Save as CSVCSV / 文本

这张表建议贴在编辑器旁边,写脚本时随时对照。

2.2 脚本变量、循环与条件判断

Praat 脚本的变量命名不区分类型,但赋值方式有讲究。数值变量直接写x = 1,字符串变量要加$后缀,比如name$ = "test"。数组用[]索引,从 1 开始而不是 0,这一点跟大多数编程语言不同,新手极易踩坑。

下面是一个批量读取文件夹内所有 wav 文件、提取基频并保存为文本的脚本骨架:

# 定义输入输出目录 input_dir$ = "/path/to/wavs/" output_dir$ = "/path/to/results/" # 创建文件列表 Create Strings as file list: "fileList", input_dir$ + "*.wav" n_files = Get number of strings # 循环处理每个文件 for i from 1 to n_files selectObject: "Strings fileList" filename$ = Get string: i base$ = filename$ - ".wav" # 读取音频 Read from file: input_dir$ + filename$ sound = selected("Sound") # 提取基频 selectObject: sound To Pitch: 0, 75, 600 pitch = selected("Pitch") # 获取基频值并写入文件 selectObject: pitch mean_f0 = Get mean: 0, 0, "Hertz" writeFileLine: output_dir$ + base$ + "_f0.txt", mean_f0 # 清理对象,避免内存堆积 selectObject: sound, pitch Remove endfor

逻辑说明:先创建文件列表对象,拿到文件数量,然后逐个读取。To Pitch的三个参数分别是时间步长(0 表示自动)、最低基频、最高基频。Get mean取整个音段的平均基频。最后用Remove清理对象,否则处理几百个文件后 Praat 会卡死。

参数怎么改:最低和最高基频要根据说话人调整。成年男性常用 75–300 Hz,成年女性常用 100–500 Hz,儿童可能到 600 Hz。设窄了会丢基频,设宽了会引入噪声,这个区间得根据你的数据来。

2.3 标注文件 TextGrid 的读写

TextGrid 是 Praat 标注的核心格式。脚本里读取 TextGrid 并提取标注内容,是批量分析前的必经步骤。下面这段代码演示如何遍历 TextGrid 的每个区间并输出标注文本和对应时间:

Read from file: "/path/to/annotation.TextGrid" tg = selected("TextGrid") # 获取层数和区间数 n_tiers = Get number of tiers for t from 1 to n_tiers tier_name$ = Get tier name: t n_intervals = Get number of intervals: t for i from 1 to n_intervals label$ = Get label of interval: t, i if label$ <> "" start = Get start time of interval: t, i end = Get end time of interval: t, i appendInfoLine: tier_name$, " ", label$, " ", start, " ", end endif endfor endfor

这里的关键是Get label of interval返回空字符串时表示该区间无标注,用if label$ <> ""过滤掉。appendInfoLine把结果输出到 Info 窗口,也可以改成writeFileLine直接写文件。

3. 用 Praat 做批量声学分析:从脚本到 CSV 的完整链路

3.1 批量提取基频、强度和共振峰

单独提取一个文件的基频很简单,但研究或工程场景往往需要处理几十上百个文件,并且要把多个声学参数合并到一张表里。手册里给了一个完整的批量处理模板,我把它拆成可复用的步骤。

第一步,准备一个文件夹,里面放所有 wav 文件,命名统一,比如speaker01_001.wav。第二步,确定你要提取的参数:基频均值、基频标准差、强度均值、第一共振峰、第二共振峰。第三步,用脚本遍历所有文件,每处理一个就往 Table 对象里追加一行。

# 创建结果表 Create Table with column names: "results", 0, ... "file f0_mean f0_sd intensity_mean f1_mean f2_mean" input_dir$ = "/path/to/wavs/" output_file$ = "/path/to/results.csv" Create Strings as file list: "list", input_dir$ + "*.wav" n = Get number of strings for i from 1 to n selectObject: "Strings list" fname$ = Get string: i base$ = fname$ - ".wav" Read from file: input_dir$ + fname$ snd = selected("Sound") # 基频 selectObject: snd To Pitch: 0, 75, 500 pit = selected("Pitch") f0_mean = Get mean: 0, 0, "Hertz" f0_sd = Get standard deviation: 0, 0, "Hertz" # 强度 selectObject: snd To Intensity: 100, 0 int = selected("Intensity") int_mean = Get mean: 0, 0, "energy" # 共振峰 selectObject: snd To Formant (burg): 0, 5, 5500, 0.025, 50 fmt = selected("Formant") f1 = Get mean: 1, 0, 0, "Hertz" f2 = Get mean: 2, 0, 0, "Hertz" # 写入表格 selectObject: "Table results" Append row row = Get number of rows Set string value: row, "file", base$ Set numeric value: row, "f0_mean", f0_mean Set numeric value: row, "f0_sd", f0_sd Set numeric value: row, "intensity_mean", int_mean Set numeric value: row, "f1_mean", f1 Set numeric value: row, "f2_mean", f2 # 清理 selectObject: snd, pit, int, fmt Remove endfor selectObject: "Table results" Save as comma-separated file: output_file$

逻辑说明:Create Table with column names先建一张空表,列名自己定。每处理完一个文件,Append row加一行,然后用Set string value和Set numeric value填数据。最后Save as comma-separated file导出 CSV。

参数注意:To Formant (burg)的五个参数分别是时间步长、最大共振峰数量、最大频率、窗口长度、预加重。最大频率根据采样率来,16 kHz 采样设 5500 Hz 左右,44.1 kHz 采样可以设到 8000 Hz 以上。窗口长度一般 0.025 秒,预加重 50 Hz 是默认值,通常不用改。

3.2 把结果整理成可分析的 CSV

导出的 CSV 可以直接拖进 Excel、R 或 Python 做后续统计。但有几个细节要注意:Praat 导出的 CSV 默认用逗号分隔,如果文件路径里有逗号会出问题,所以命名时避开逗号。另外,基频和共振峰的缺失值在 Praat 里可能显示为--undefined--,导入 Python 后要处理成 NaN。

我一般会在 Python 里做一步清洗:

import pandas as pd df = pd.read_csv("results.csv") df = df.replace("--undefined--", pd.NA) df = df.apply(pd.to_numeric, errors="ignore") df.to_csv("results_clean.csv", index=False)

这样后续做混合效应模型或画图都不会因为格式问题翻车。

3.3 脚本调试与错误定位

Praat 脚本报错信息往往很模糊,比如「Command not available for current selection」这种,本质是你选错了对象。调试时我习惯在关键步骤后加appendInfoLine打印当前对象类型和数量,确认流水线没跑偏。

另一个常见问题是对象泄漏。循环里创建了对象但没 Remove,跑几十个文件后内存暴涨,Praat 直接无响应。所以每个循环末尾一定要清理临时对象。手册里专门用一节讲这个,算是血泪经验。

4. 避坑与常见问题:那些手册没写但一定会遇到的坑

4.1 基频提取结果全是 0 或 undefined

现象:脚本跑完,CSV 里 f0_mean 一列全是 0 或者--undefined--。

原因:最常见的是基频范围设错了。比如男声录音你设了 200–500 Hz,实际基频在 100 Hz 左右,Praat 直接判定为无声段。另一个原因是音频本身信噪比太低,或者有直流偏移。

解决:先用一个文件手动跑To Pitch,在编辑器里看基频曲线是否合理。范围从 75–500 Hz 开始试,再根据说话人调整。如果音频质量差,先做降噪或归一化。

4.2 TextGrid 区间标注读取为空

现象:遍历 TextGrid 时,明明在编辑器里看到有标注,脚本读出来全是空字符串。

原因:TextGrid 可能有多层,你读的那一层是空的,标注在另一层。或者区间边界没对齐,Get label of interval取的是区间索引,不是时间点。

解决:先用Get number of tiers和Get tier name确认层名,再定位到有标注的那一层。如果标注是点标注(PointTier)而不是区间标注(IntervalTier),要用Get label of point而不是Get label of interval。

4.3 批量处理时 Praat 卡死或崩溃

现象:跑几十个文件后 Praat 无响应,或者直接闪退。

原因:对象没清理,内存堆积。Praat 不像 Python 有自动垃圾回收,每个Read from file和To Pitch都会创建新对象,不 Remove 就一直在。

解决:每个循环末尾加selectObject: 所有临时对象然后Remove。另外,处理超大批量时,可以分批跑,每 50 个文件重启一次 Praat。

4.4 导出的 CSV 中文乱码

现象:标注文本是中文时,导出的 CSV 用 Excel 打开乱码。

原因:Praat 默认用 UTF-8 编码写文件,Excel 在中文系统下默认用 GBK 打开。

解决:用记事本打开 CSV 再另存为 ANSI 编码,或者在 Python 里用encoding="utf-8-sig"读取后再导出。更彻底的办法是标注时就用英文或拼音,避免编码问题。

4.5 脚本里的路径分隔符在 Windows 和 Mac 下不通用

现象:在 Mac 上写好的脚本,拿到 Windows 上跑,报「文件不存在」。

原因:Mac 用/,Windows 用\,虽然 Praat 在 Windows 下也支持/,但如果你从资源管理器复制路径,默认是\。

解决:统一用/,Praat 跨平台都认。或者用homeDirectory$和preferencesDirectory$这类内置变量拼接路径,减少硬编码。

5. 进阶技巧:用 Praat 做脚本化标注与批量修改

5.1 自动生成 TextGrid 并预标注

有时候你不需要手动标注,而是想根据静音段自动切分,生成初始 TextGrid,再人工修正。Praat 可以结合To TextGrid (silences)实现:

Read from file: "/path/to/audio.wav" snd = selected("Sound") # 自动检测静音段生成 TextGrid selectObject: snd To TextGrid (silences): 100, 0, -25, 0.1, 0.05, "silent", "voiced" tg = selected("TextGrid") # 保存 Save as text file: "/path/to/auto.TextGrid"

参数说明:100是分析步长,0是起始时间,-25是静音阈值(dB),0.1是最短静音间隔,0.05是最短有声段。生成的 TextGrid 有两层:silent 和 voiced。这个结果可以直接导入标注工具做修正,省掉大量手动切分时间。

5.2 批量修改 TextGrid 标注内容

如果发现标注文件里某个标签写错了,比如把所有「a」改成「aa」,可以用脚本批量替换:

input_dir$ = "/path/to/textgrids/" Create Strings as file list: "list", input_dir$ + "*.TextGrid" n = Get number of strings for i from 1 to n selectObject: "Strings list" fname$ = Get string: i Read from file: input_dir$ + fname$ tg = selected("TextGrid") n_tiers = Get number of tiers for t from 1 to n_tiers n_int = Get number of intervals: t for j from 1 to n_int label$ = Get label of interval: t, j if label$ == "a" Set interval text: t, j, "aa" endif endfor endfor Save as text file: input_dir$ + fname$ selectObject: tg Remove endfor

这个模板可以扩展成任意标签替换,只要改if条件里的字符串就行。

5.3 验证脚本正确性的笨办法

写完一个批量脚本,别急着跑全量数据。先拿 3 个文件跑一遍,手动核对第一个文件的基频均值、共振峰数值跟 Praat 编辑器里看到的是否一致。确认无误再跑全量。这个习惯帮我省过很多次返工。

从那以后我每次写新脚本,都强制先跑小样本验证,再上全量。希望这份手册能帮你少走点弯路。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进