文章目录
前言
先展示下程序效果:
python模拟CW通联发报与译码
CW是等幅电报通信(Continuous Wave)的英文字头简称,CW电报通信是业余电台众多通信方式中主要的常用联络方式之一,在业余电台通信联络中通称为CW方式。
由于很多人对CW中使用的电报码还不是很熟悉,更多只是电视剧谍报人员收发报过程中听过到的滴滴答答的声音。
那么电报码到底是什么样的?它的消息发送有什么规律和要求呢?本文将为您一一揭晓。甚至您可以自己编一段消息来体验下发报的过程和声音。当然收报解译需要一个熟练过程。
CW的学习步骤简单的讲只有3个字:“背”“抄”“发”, 那就是背码表,练抄收,练发报的一个过程。
本文将向您展示什么是莫尔斯电码,以及如何使用其发送和接收英文、中文消息。通过Python程序模拟CW电报发报与译码,包括英文和中文,方便练习发报节奏和听音解码。感兴趣的朋友可以试试。代码均已测试OK。
一、什么是莫尔斯电码(也有翻译为摩尔斯)
电报出现于19世纪,是人类最早用电信号传送信息的方式,在19世纪和20世纪也是主要的通信方式之一。进入21世纪后,电报这种通信方式基本不再使用。但在业务无线电里,它依然活跃,而且由于设备的升级,普通人只要考取的业余无线电B类操作证也可以架台和原方的HAM进行CW的通联。这里就有必要解释下电报的工作原理。
1. 电报的工作原理:
发报方将文字转换成特定的编码,然后以电信号把这些编码发送出去;收报方抄收这些编码,然后翻译成文字。双方都有一个相同的代码本,上面记载了文字和编码的对应关系。显然,使用私有的代码本,可避免无关收报方破译电报文本。
电报通常使用国际摩尔斯电码进行收发报。摩尔斯电码使用点(·)和划(-)两种符号的特定组合表示不同的字符,在用声音表示时,其中点(·)为短信号,一个时间单位,读作滴,划(-)为长信号,三个时间单位,读作嗒;两个信号间隔一个时间单位,字符间隔三个时间单位,单词间隔七个时间单位。
2. 莫尔斯电码编码表:
国际莫尔斯电码(字母)
字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
A | ·- | B | -··· | C | -·-· | D | -·· | E | · | F | ··-· | G | –· |
H | ···· | I | ·· | J | ·— | K | -·- | L | ·-·· | M | – | N | -· |
O | — | P | ·–· | Q | –·- | R | ·-· | S | ··· | T | - | U | ··- |
V | ···- | W | ·– | X | -··- | Y | -·– | Z | –·· |
国际莫尔斯电码(数字)
字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 |
---|---|---|---|---|---|---|---|---|---|
1 | ·---- | 2 | ··— | 3 | ···– | 4 | ····- | 5 | ····· |
6 | -···· | 7 | –··· | 8 | —·· | 9 | ----· | 0 | ----- |
国际莫尔斯电码(标点)
字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 |
---|---|---|---|---|---|---|---|---|---|---|---|
. | ·-·-·- | : | —··· | , | –··– | ; | -·-·-· | ? | ··–·· | = | -···- |
’ | ·----· | / | -··-· | ! | -·-·– | - | -····- | _ | ··–·- | " | ·-··-· |
( | -·–· | ) | -·–·- | $ | ···-··- | & | ·-··· | @ | ·–·-· | + | ·-·-· |
二、使用Python将英文消息转莫尔斯电码并模拟发报与解码
1. 生成代码字典
# 莫尔斯代码字典
MORSE_CODE_DICT = { 'A':'.-', 'B':'-...', 'C':'-.-.', 'D':'-..', 'E':'.', 'F':'..-.', 'G':'--.',
'H':'....', 'I':'..', 'J':'.---', 'K':'-.-', 'L':'.-..', 'M':'--', 'N':'-.',
'O':'---', 'P':'.--.', 'Q':'--.-', 'R':'.-.', 'S':'...', 'T':'-',
'U':'..-', 'V':'...-', 'W':'.--', 'X':'-..-', 'Y':'-.--', 'Z':'--..',
'1':'.----', '2':'..---', '3':'...--', '4':'....-', '5':'.....',
'6':'-....', '7':'--...', '8':'---..', '9':'----.', '0':'-----',
'.':'·-·-·-', ':':'---···', ',':'--··--', ';':'-·-·-·', '?':'··--··', '=':'-···-',
"'":'·----·', '/':'-··-·', '!':'-·-·--', '-':'-····-', '_':'··--·-', '"':'·-··-·',
'(':'-·--·', ')':'-·--·-', '$':'···-··-', '&':'·-···', '@':'·--·-·', '+':'·-·-·'}
由于字典默认使用单引号定义键名,而英文字符单引号也是字符之一,故这里使用双引号,解决的键名定义问题"‘":’·----·’
如果使用双引号定义字符串,那么字符串里如果需要用到双引号,需要使用转移符,修改为:\" 即可。
2. 模拟发报与译码(完整源代码)
# -*- coding: utf-8 -*-
# 莫尔斯代码字典
MORSE_CODE_DICT = { 'A':'.-', 'B':'-...', 'C':'-.-.', 'D':'-..', 'E':'.', 'F':'..-.', 'G':'--.',
'H':'....', 'I':'..', 'J':'.---', 'K':'-.-', 'L':'.-..', 'M':'--', 'N':'-.',
'O':'---', 'P':'.--.', 'Q':'--.-', 'R':'.-.', 'S':'...', 'T':'-',
'U':'..-', 'V':'...-', 'W':'.--', 'X':'-..-', 'Y':'-.--', 'Z':'--..',
'1':'.----', '2':'..---', '3':'...--', '4':'....-', '5':'.....',
'6':'-....', '7':'--...', '8':'---..', '9':'----.', '0':'-----',
'.':'·-·-·-', ':':'---···', ',':'--··--', ';':'-·-·-·', '?':'··--··', '=':'-···-',
"'":'·----·', '/':'-··-·', '!':'-·-·--', '-':'-····-', '_':'··--·-', '"':'·-··-·',
'(':'-·--·', ')':'-·--·-', '$':'···-··-', '&':'·-···', '@':'·--·-·', '+':'·-·-·'}
def en2morse(message):
# 将字符转为莫尔斯代码字符串
message = ' '.join(message.split()) # 将多个空格替换为一个,避免程序报错。
cipher = ''
for letter in message:
if letter != ' ':
cipher += MORSE_CODE_DICT[letter] + ' '
else:
cipher += ' '
return cipher
def morse2en(code):
# 将莫尔斯代码字符串转为字符
code = code.strip() # 剔除前后空格,避免程序报错。
code += ' '
decipher = ''
citext = ''
for letter in code:
if (letter != ' '):
i = 0
citext += letter
else:
i += 1
if i == 2 :
decipher += ' '
else:
decipher += list(MORSE_CODE_DICT.keys())[list(MORSE_CODE_DICT.values()).index(citext)]
citext = ''
return decipher
def morse2beep(code):
# 对莫尔斯字符串转为声音
import winsound,time,sys
# 间隔时间:滴=1t,嗒=3t,滴嗒间=1t,字符间=3t,单词间=7t
di = 80
da = di*3
sp = di/1000
chr_sp = di*3/1000
word_sp = di*7/1000
vol = 600
for i in range(len(code)):
if code[i] == '.':
winsound.Beep(vol,di)# 其中vol表示声音大小,di表示发生时长,1000为1秒
elif code[i] == '-':
winsound.Beep(vol,da)
elif code[i] == ' ':
if i < len(code)-1 and code[i+1] == ' ' :
time.sleep(word_sp)
else:
time.sleep(chr_sp)
else:
time.sleep(sp)
print(code[i],end='')
sys.stdout.flush()
print()
def msg2beep2msg(msg):
# 将消息转换为莫尔斯代码并显示,再通过声音模拟发报,最后进行译码。
print(message)
ret = en2morse(message.upper()) # 消息转为莫尔斯代码
print(ret)
morse2beep(ret) # 通过声音展示莫尔斯代码,模拟发报
ret = morse2en(ret) # 莫尔斯代码转为消息,模拟解码
print(ret)
if __name__ == '__main__':
message = "CQ CQ CQ DE BI9ABG BI9ABG BI9ABG PSE K " # 字符串里使用:”"“,需要修改为:”\"“。
msg2beep2msg(message)
三、使用Python将中文消息转莫尔斯电码并模拟发报
1. 发送中文怎么办?
在电话普及前,已开始使用电报。但要将几千个汉字发成电报貌似比26个英文字母要复杂,于是人们想出对汉字使用4位数字进行编码的方案,也就是汉字电报码。
汉字电报码使用四位数字标识一个汉字,如:我的代码是 2053,西安分别是6007 1344。
既然知道了逻辑,我们把汉字电报码下载下来,使用程序做成字典,调用的时候去查询即可。由于字典太大,我们将汉字电报码保存在hzdbm.txt,和程序放在同一个目录。
当然发报人和收报人需要使用同一个字典,才可以正常译码。这也就是密码本的来由。这也就是电视中破译电报桥段的来由。无线电波信号是公开传递的,但没有密码本,自然收到也无法译码。你也可以自己定义字典,可以定义属于你的专属密码本。不过,作为一般大家都适用通用电码本。下面为大家准备了一个电码字典。
中文电报码-其它文档类资源-CSDN文库 https://download.csdn.net/download/popboy29/87522106
2. 编码与译码
发报时先查字典找到对应汉字的编码,然后对数字使用莫尔斯电码发报;解译的过程和编码的过程相反,先将收到的莫尔斯电码继续下来,4位数字对应一个汉字,然后再按数字查字典找到对应的汉字,就可以看到中文消息内容。
3. 模拟中文发报与译码(完整源代码)
首先将第二部分代码完整保存为morsecode.py,再将以下内容和hzdbm.txt一同保存在同一目录。
from morsecode import *
def hz_morsecode():
# 将汉字电报码转为dict,方便调用。由于数字唯一,故使用4位数字字符串作为键名。
import os
HZ_CODE_DICT = {}
with open(os.path.dirname(os.path.abspath(__file__))+'\\hzdbm.txt',encoding='utf-8-sig') as file:
line = file.read()
line = line.replace('\n', '') # 删除末尾的换行符
line_list = line.strip().split(" ")
for i in range(len(line_list)):
HZ_CODE_DICT[line_list[i][1:5]] = line_list[i][0:1]
return HZ_CODE_DICT
HZ_CODE_DICT = hz_morsecode()
# print(HZ_CODE_DICT)
def get_keys(d, value):
# 根据值来查找键
return [k for k, v in d.items() if v == value]
def get_hz_morsecode(hz_msg):
# 将字符转为莫尔斯代码字符串
hz_msg = ''.join(hz_msg.split()) # 将多个空格替换为一个,避免程序报错。
cipher = ''
hz_msg = hz_msg.upper() # 英文需要先全部改为大写
for hz in hz_msg:
if hz in MORSE_CODE_DICT.keys():
# 如果是英文字符后数字,直接输出
cipher += en2morse(hz) + ' '
elif hz == ' ':
cipher += ' '
else:
# 如果是汉字字符,转换为4位数字再转莫尔斯码输出
# print(get_keys(HZ_CODE_DICT, hz))
for i in get_keys(HZ_CODE_DICT, hz)[0]:
cipher += en2morse(i) + ' '
return cipher
def hz2beep2hz(msg):
# 将汉字消息逐字转换为4位代码,再将数字转换为莫尔斯代码并显示,再通过声音模拟发报,最后进行译码。
print(hz_msg)
ret = get_hz_morsecode(hz_msg)
print(ret)
morse2beep(ret) # 通过声音展示莫尔斯代码,模拟发报
ret = morse2en(ret) # 莫尔斯代码转为消息,模拟解码
print(ret)
#
import re
hz_code_str = ret.replace(' ', '')
print(hz_code_str)
hz_code_str = re.findall(r'[0-9]{4}', hz_code_str)
print(hz_code_str)
for i in hz_code_str:
print(HZ_CODE_DICT[i],end='')
print()
if __name__ == '__main__':
hz_msg = "声音传递汉字"
hz2beep2hz(hz_msg)
运行结果如下:
声音传递汉字
… .---- .---- -… --… …— ----. ----. ----- …— --… —… -… -… --… --… …-- …-- … …— .---- …-- .---- -…
… .---- .---- -… --… …— ----. ----. ----- …— --… —… -… -… --… --… …-- …-- … …— .---- …-- .---- -…
5 1 1 6 7 2 9 9 0 2 7 8 6 6 7 7 3 3 5 2 1 3 1 6
511672990278667733521316
[‘5116’, ‘7299’, ‘0278’, ‘6677’, ‘3352’, ‘1316’]
声音传递汉字
相比于英文(26个字母+数字+标点符号)莫尔斯码,汉字只需要记住以下0-9数字的莫尔斯码即可(规律很明显,其实很简单),然后就是收到的消息四位数字一分隔,然后去查字典就好。小学生也可以很快掌握。
字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 |
---|---|---|---|---|---|---|---|---|---|
1 | ·---- | 2 | ··— | 3 | ···– | 4 | ····- | 5 | ····· |
6 | -···· | 7 | –··· | 8 | —·· | 9 | ----· | 0 | ----- |
总结
CW,等幅电波,在无线电通信中,特指等幅电报。由于是形如“1、0”的二进制信号,故一般利用摩尔斯电码发送信息。它通过电键控制发信机产生短信号".“(点)和长信号”–"(划),并利用其不同组合表示不同的字符,从而组成单词和句子。与其他无线电通信方式相比,CW优点是所需设备简单、占用频带窄、发射效率高、在同等条件下通信距离更远。但是需要值机员熟练掌握收发报技术。
随着通讯科技的发展,电报已不再是主要的通讯方法。自从电话网络数字化以后,电报通讯变成为数位通讯网络内其中一种以文字通讯的应用,在传真机普及后更被传真所取代。当互联网及行动通讯日渐广泛使用以后,电报更进一步被电子邮件及短信所取代。一般人已不会使用电报通讯。
电报业务虽然已经过时,但是CW通联在业务无线电里依然收到广大HAM的热爱,除了短波CW传输距离远以外,电报这种最早出现的电子信息传递方式依然有其拥趸。也是一种情怀,也许是自由通信的热爱,也许是对古老通信方式的好奇,让我们一起CW通联吧。
注意:使用短波设备CW通联需要首先获得业余无线单B类操作证,并报备后方可设台通联。
(使用Python程序模拟发报、译码先在本地体验一下,这个就不用了。^-^)