说起英语900句,飞行员们都应该很熟悉,不过本篇并非介绍飞行员如何掌握英语陆空通话,而是讨论AI时代,如何教自己的电脑在驾驶舱听懂ICAO英语。
基本工具
1、Python,这是一种简便的电脑编程语言,入门需要半天,学懂需要一天。如果你还没学,未来十年内可能出现聊天障碍。
2、ChatGPT,网上小程序很多,大部分能直接用,CSDN提供的ChitGPT也一样效果。最大的好处是可以直接写优质代码,效率提升百倍。
基本思路
1、打开电脑麦克风监听,如果听到有人说话则录音,说完后将录音另存为wav文件;
2、识别wav文件的语音,转为文字显示出来;
3、利用公开的英语900句,训练数据以提升识别率;
4、让电脑朗读识别出来的文字,达到复诵效果。
实现过程
第一步 监听
将想法写给ChatGPT,生成代码如下:
import pyaudio
import wave
import audioop
import math
# 设定参数
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 1024
MIN_VOLUME = 500
# 实例化pyaudio对象
p = pyaudio.PyAudio()
# 打开麦克风录音
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print("* 开始录音")
# 定义一个空的缓冲区
frames = []
# 是否正在录音标志位
recording = False
# 循环录音
while True:
# 读取音频数据
data = stream.read(CHUNK)
# 计算音量大小
rms = audioop.rms(data, 2)
volume = math.log10(rms) * 20
print(volume)
# 如果音量大于阈值,则认为开始录音
if volume > MIN_VOLUME:
recording = True
# 如果正在录音,则将音频数据存入缓冲区
if recording:
frames.append(data)
# 如果音量小于阈值,并且正在录音,则认为录音结束
if volume < MIN_VOLUME and recording:
recording = False
print("* 录音结束")
# 停止录音
stream.stop_stream()
stream.close()
p.terminate()
# 保存音频文件
wf = wave.open("output.wav", 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
print("* 音频文件已保存")
# 退出循环
break
print("* 程序结束")
阅读理解代码后知道,AI试图用音量区分话音,通过比较安静时和说话时的分贝量,确定是否录音,录音后保存为output.wav文件。
但运行后发现并不能录音,检查代码发现阈值MIN_VOLUME设置太高,一般情况下VOLUME在55左右,说话则达到70-80,说完又回到55左右,因此更改启动阈值为65,结束阈值为65-10,测试通过,现在可以正常录音。
这部分还可以专题优化,因不是本文重点,不再赘述。
第二步 识别
请ChatGPT写代码,将wav文件中的语音识别为文字。结果如下:
import speech_recognition as sr
# 创建识别器实例
r = sr.Recognizer()
# 定义音频文件路径
audio_file = 'audio.wav'
# 使用WAV格式打开音频文件
with sr.AudioFile(audio_file) as source:
# 从音频文件中读取数据
audio_data = r.record(source)
# 调用谷歌语音识别API识别音频并返回文字结果
text = r.recognize_google(audio_data, language='en-US')
# 打印识别结果
print(text)
没想到这么短的代码就完成了语音识别。不过呢,把audio.wav换成output.wav之后,直接报错了,说google无法访问。咨询ChatGPT得知,这段代码开头调用的speech_recognition模块,支持多种线上API,也支持本地模块,当前阶段在驾驶舱肯定很难上网,因此需要换成本地模块Sphinx。
安装pocketsphinx模块后,把代码中的google换成sphinx,再次运行,就发现可以英语语音识别了。
但是但是,这个识别结果,非常雷人。
语音原文:FOLLOW THE STANDARD MISSED APPROACH PROCEDURE, THE VISIBILITY IS IMPROVED NOW, EXPECT RADAR VECTORS FOR ANOTHER APPROACH, RIGHT TURN HEADING 090 CLEARED FOR ILS RUNWAY 18 LEFT
识别结果:fall is dead and me stuck right you procedure the visibility supremes now expect to write 'em back to talk about an inch time ron hennings urine on his right clinical while it's wrong when one is left.
当然,英语陆空通话和普通交流英语存在一定差别,再加上各国口音、背景噪音等原因,不能对结果期望太高。但是挫到这么离谱显然不能接受,肯定有解决办法。
第三步 认识斯芬克斯
刚才提到,本地识别需要加载sphinx模块,全称是CMU Sphinx,出自卡耐基梅隆大学(CMU)的开源项目。那我们就来学习一下Sphinx怎么处理语音的:
1、声学模型:把wav文件切分成小片段,分析每段的声音数据,以及前后关联特征,形成特征向量(向量就是一长串数字,每一串等长,类似一把烤肉串,串串不同);
2、语音字典:分析每个单词由哪些声学模型组成,不同情况下的变体又是如何,可以通过运用机器学习算法去学习得到一些复杂的函数去完成映射功能。
3、语义模型:上面这个案例之所以失败,一个重要原因是陆空通话的语序和正常英语不太一样。单词间的先后顺序有一定的规律性,这可以理解为语义模型,通过对大量语句的训练可以得到。
理解了Sphinx,就知道,可以通过对上面三个模型进行数据训练,从而提高识别率。
第四步 训练实战
唾手可得的数据是网上公开的英语900句,这个数据拿来训练语音字典和语义模型非常合适,词汇量、语义语序都很般配。
卡耐基梅隆大学直接提供了训练工具,要求很简单,提供几千个语句样本即可,但是要去掉标点符号。考虑到逗号和句号都是语音的断点,所以先把所有句子按逗号句号处理成短句,然后去掉句尾的标点符号,顺便去掉句首的空格,ChatGPT给出的代码:
with open('9001.txt', 'r') as file:
lines = file.readlines()
new_lines = []
for line in lines:
line = line.strip()
if line:
if line[0] == ' ':
line = line[1:]
if line[-1] in ['.', ',', ';', ':', '!', '?']:
line = line[:-1]
new_lines.append(line)
with open('9002.txt', 'w') as file:
file.write('\n'.join(new_lines))
没有出错,直接出结果。
接下来是处理陆空通话的独特性:
1、对比发现,单字母(一般用于滑行道、通波号),双字母(例如NDB导航台二字码),三字母(例如VOR台三字码,但要排除CAT)均使用航空字母发音,为避免训练出错,全部替换为航空词汇,例如A替换为Alpha,B替换为Bravo,...;
2、900句中出现的特定词包括:VOR、DME、NDB、ILS、LDA、QNH、RVR、ADS-B、RNAV、FMS、IMC、VMC、RVSM、CPDLC、MEA、RNP、GPS、CDU、RA、EGT、GPWS、APU、FOD、ETA、CPR、ATC、SID、VHF、HF、ELT、EGT、AC、DC,这些均使用字母原音,所以全部插入连接线,避免被误认为航空字母发音,例如VOR要改成V-O-R;
3、三字母CAT和其余四字母组合、五字母组合则使用单词发音,不要改;
4、检测runway XX R或L,把R替换为Right,L替换为Left,XX表示跑道方向的两位数字;
5、根据语言习惯,需要替换00 feet、000 feet为hundred feet、thousand feet
6、所有小数点替换成decimal,QNH后的小数点则清除
以上1、2、4、5、6可以让ChatGPT给出代码,4、5、6也可以手工处理。
import re
# 逐行读取文本文件
with open('9004.txt', 'r') as file:
lines = file.readlines()
# 查找每行前后均为空格的大写字母组合
replace_dict = {'A': 'alpha ', 'B': 'bravo ', 'C': 'Charlie ','D': 'Delta ','E': 'Echo ','F':'Foxtrot ',
'G': 'Golf ','H': 'Hotel ','I': 'India ','J':'Juliet ','K': 'Kilo ','L': 'Lima ',
'M': 'Mike ','N': 'November ','O': 'Oscar ','P': 'Papa ','Q': 'Quebec ','R': 'Romeo ',
'S': 'Sierra ','T': 'Tango ','U': 'Uniform ','V': 'Victor ','W': 'Whiskey ','X': 'X-Ray ',
'Y': 'Yankee ','Z': 'Zulu '}
for i in range(len(lines)):
matches = re.findall(r'\s([A-Z]{1,3})\s', lines[i])
#print(matches)
while 'CAT' in matches:
matches.remove('CAT')
for match in matches:
#print(match)
replace_str = match
# 将 A 替换成 alpha,B 替换成 bravo,C 替换成 Charlie
for old, new in replace_dict.items():
replace_str = replace_str.replace(old, new)
# 替换本行中匹配项
lines[i] = lines[i].replace(match, replace_str)
# 将修改后的文本保存到 9006.txt
with open('9006.txt', 'w') as file:
for line in lines:
file.write(line)
至此,900句的预处理已经完成,考虑到实战需要,把数字0-9、字母A-Z每个一行填入文本文件,再从网上下载全球航空公司callsign列表,从中选取熟悉的100家,也填入文本文件,到CMU的网站做语义模型训练:
http://www.speech.cs.cmu.edu/tools/lmtool-new-debug.html
稍等几分钟,训练完毕,数据打包下载,解压缩后提取xxxx.lm 、xxxx.dic两个文件,前者是语义模型,后者是语音字典。
此时对字典文件xxxx.dic做微调,修正所有3、4、5、9、thousand的特殊读音,这样更严谨。
在本机上找到pocketsphinx-data文件夹,里面有en-US文件夹,意思是之前用的美音英语模型,现在要换掉,复制这个文件夹并另起名字aviation,并列存放,进入aviation,看到language-model.lm.bin和pronounciation-dictionary.dict两个文件,把数据包里的xxxx.lm改名为前者,xxxx.dic改名为后者,然后覆盖整两个文件。
语音字典和语义模型替换完毕,再试一次:
import speech_recognition as sr
# 创建识别器实例
r = sr.Recognizer()
# 定义音频文件路径
audio_file = 'output3.wav'
# 使用WAV格式打开音频文件
with sr.AudioFile(audio_file) as source:
# 从音频文件中读取数据
audio_data = r.record(source)
# 调用谷歌语音识别API识别音频并返回文字结果(sphinx为本地,google为API)
text = r.recognize_sphinx(audio_data, language="aviation")
# 打印识别结果print(text)
string_to_save = text
file_name = "outext.txt"
with open(file_name, "w") as f:
f.write(string_to_save)
print("已保存字符串到文件 {} 中。".format(file_name))
找一段空地对话录音,最好是900句以外的,试一下:
语音原文:FOLLOW THE STANDARD MISSED APPROACH PROCEDURE, THE VISIBILITY IS IMPROVED NOW, EXPECT RADAR VECTORS FOR ANOTHER APPROACH, RIGHT TURN HEADING 090 CLEARED FOR ILS RUNWAY 18 LEFT
识别结果:FOLLOW THE STANDARD MISSED APPROACH PROCEDURE THE VISIBILITY IS IMPROVED NOW EXPECT RADAR VECTORS FOR ABOUT RIGHT TURN RIGHT HEADING 0900 CLEARED FOR I-L-S RUNWAY 18 LEFT
可以说,训练修成了果,看上去能用,但是这可是老师的标准录音,如果换成自己说,或者女声,误差又开始增加,还需要考虑进一步的训练,包括:
1、从公开的《航空通信程序指南》上获取更多的语句样本,方法向ChatGPT索取,然后再次训练语音字典和语义模型,识别效果会继续增强;
2、考虑到噪音、日韩口音、美国口音、法国口音、东南亚口音等因素,可能需要对声学模型进行训练,这需要大量的录音数据,一个人完成不了,需要团队,有能力有兴趣的可以私信。
第五步 复诵
继续请ChatGPT写代码,朗读文本:
import pyttsx3
import os
# 安装pyttsx3:pip install pyttsx3
# 安装pywin32:pip install pypiwin32
# 设置朗读语音
engine = pyttsx3.init()
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[0].id) # 选择第一个语音引擎
# 读取txt文件
filename = 'outext.txt' # 更改为你的txt文件名
if os.path.exists(filename):
with open(filename, 'r', encoding='utf-8') as f:
content = f.read()
# 朗读英文文本
engine.say(content)
engine.runAndWait()
else:
print('文件不存在!')
朗读很容易实现,目前的BUG是,数字被汉语读出,需要了解原因。折中办法是,朗读前把数字替换为英文单词。
后记
做这个软件,纯粹是想了解AI加持下如何梦想成真,不专业的人干专业的事会怎么样。
以当前的技术,已经可以用海量QAR数据训练出操作模型,用大量通话录音可以训练出对话模型,按照十四五规划,2025年民航将全面实现机上宽带互联,届时出现能理解指令、精通操作、通话自如的AI副驾驶,将不是个新鲜事。
由于开发过程利用了大量开源代码,受license所限,所有内容可以分享、可以继续开发,请不要试图在此基础上开发商用版本。
深入了解民航,请进入下列链接: