271 lines
9.0 KiB
Python
271 lines
9.0 KiB
Python
import struct
|
||
import math
|
||
|
||
def encode_ais_fields():
|
||
"""编码AIS消息字段并打印解码结果"""
|
||
# 初始化二进制位列表
|
||
bits = []
|
||
|
||
# 示例数据
|
||
message_id = 1 # 消息ID (6 bits)
|
||
repeat_indicator = 0 # 转发指示符 (2 bits)
|
||
user_id = 123456789 # 用户ID/MMSI (30 bits)
|
||
navigation_status = 8 # 导航状态 (4 bits) - 航行中
|
||
rot = -128 # 旋转速率 (8 bits) - 无信息
|
||
sog = 102 # 地面航速 (10 bits) - 10.2节
|
||
position_accuracy = 1 # 位置准确度 (1 bit) - 高
|
||
longitude = 120.5 # 经度 (28 bits) - 东经120.5°
|
||
latitude = 30.5 # 纬度 (27 bits) - 北纬30.5°
|
||
cog = 900 # 地面航线 (12 bits) - 90.0°
|
||
true_heading = 90 # 实际航向 (9 bits) - 90°
|
||
timestamp = 30 # 时戳 (6 bits) - UTC秒
|
||
special_maneuver = 0 # 特定操纵指示符 (2 bits)
|
||
spare = 0 # 备用 (3 bits)
|
||
raim_flag = 0 # RAIM标志 (1 bit)
|
||
comm_state = 0 # 通信状态 (19 bits)
|
||
|
||
# 添加各个字段(按照协议顺序)
|
||
bits.append(format(message_id, '06b')) # 消息ID
|
||
bits.append(format(repeat_indicator, '02b')) # 转发指示符
|
||
bits.append(format(user_id, '030b')) # 用户ID
|
||
bits.append(format(navigation_status, '04b')) # 导航状态
|
||
|
||
# 旋转速率 (8位有符号整数)
|
||
rot_bits = rot & 0xFF
|
||
bits.append(format(rot_bits, '08b'))
|
||
|
||
# 地面航速 (10位)
|
||
bits.append(format(min(sog, 1023), '010b'))
|
||
|
||
# 位置准确度 (1位)
|
||
bits.append(str(position_accuracy))
|
||
|
||
# 经度 (28位)
|
||
# 转换为1/10,000分钟单位
|
||
longitude_min = int(longitude * 60 * 10000)
|
||
bits.append(format(longitude_min & 0x0FFFFFFF, '028b'))
|
||
|
||
# 纬度 (27位)
|
||
latitude_min = int(latitude * 60 * 10000)
|
||
bits.append(format(latitude_min & 0x07FFFFFF, '027b'))
|
||
|
||
# 地面航线 (12位)
|
||
bits.append(format(min(cog, 3600), '012b'))
|
||
|
||
# 实际航向 (9位)
|
||
bits.append(format(min(true_heading, 511), '09b'))
|
||
|
||
# 时戳 (6位)
|
||
bits.append(format(min(timestamp, 63), '06b'))
|
||
|
||
# 特定操纵指示符 (2位)
|
||
bits.append(format(special_maneuver, '02b'))
|
||
|
||
# 备用 (3位)
|
||
bits.append(format(spare, '03b'))
|
||
|
||
# RAIM标志 (1位)
|
||
bits.append(str(raim_flag))
|
||
|
||
# 通信状态 (19位)
|
||
bits.append(format(comm_state, '019b'))
|
||
|
||
# 合并所有位
|
||
bit_string = ''.join(bits)
|
||
|
||
# 验证总位数
|
||
total_bits = len(bit_string)
|
||
if total_bits != 168:
|
||
print(f"警告: 总位数应为168,实际为{total_bits}")
|
||
|
||
# 将位字符串转换为字节
|
||
byte_count = total_bits // 8
|
||
ais_data = bytearray()
|
||
for i in range(byte_count):
|
||
byte_str = bit_string[i*8:(i+1)*8]
|
||
ais_data.append(int(byte_str, 2))
|
||
|
||
# 解码过程
|
||
decoded = {}
|
||
pos = 0
|
||
|
||
# 消息ID (6 bits)
|
||
decoded['消息ID'] = int(bit_string[pos:pos+6], 2)
|
||
pos += 6
|
||
|
||
# 转发指示符 (2 bits)
|
||
decoded['转发指示符'] = int(bit_string[pos:pos+2], 2)
|
||
pos += 2
|
||
|
||
# 用户ID (30 bits)
|
||
decoded['用户ID'] = int(bit_string[pos:pos+30], 2)
|
||
pos += 30
|
||
|
||
# 导航状态 (4 bits)
|
||
decoded['导航状态'] = int(bit_string[pos:pos+4], 2)
|
||
pos += 4
|
||
|
||
# 旋转速率 (8 bits)
|
||
rot_value = int(bit_string[pos:pos+8], 2)
|
||
# 转换为有符号整数
|
||
if rot_value > 127:
|
||
rot_value -= 256
|
||
decoded['旋转速率'] = rot_value
|
||
pos += 8
|
||
|
||
# SOG (10 bits)
|
||
decoded['SOG'] = int(bit_string[pos:pos+10], 2)
|
||
pos += 10
|
||
|
||
# 位置准确度 (1 bit)
|
||
decoded['位置准确度'] = int(bit_string[pos], 2)
|
||
pos += 1
|
||
|
||
# 经度 (28 bits)
|
||
longitude_value = int(bit_string[pos:pos+28], 2)
|
||
# 转换为度
|
||
longitude_deg = longitude_value / (60 * 10000)
|
||
decoded['经度'] = longitude_deg
|
||
pos += 28
|
||
|
||
# 纬度 (27 bits)
|
||
latitude_value = int(bit_string[pos:pos+27], 2)
|
||
# 转换为度
|
||
latitude_deg = latitude_value / (60 * 10000)
|
||
decoded['纬度'] = latitude_deg
|
||
pos += 27
|
||
|
||
# COG (12 bits)
|
||
decoded['COG'] = int(bit_string[pos:pos+12], 2)
|
||
pos += 12
|
||
|
||
# 实际航向 (9 bits)
|
||
decoded['实际航向'] = int(bit_string[pos:pos+9], 2)
|
||
pos += 9
|
||
|
||
# 时戳 (6 bits)
|
||
decoded['时戳'] = int(bit_string[pos:pos+6], 2)
|
||
pos += 6
|
||
|
||
# 特定操纵指示符 (2 bits)
|
||
decoded['特定操纵指示符'] = int(bit_string[pos:pos+2], 2)
|
||
pos += 2
|
||
|
||
# 备用 (3 bits)
|
||
decoded['备用'] = int(bit_string[pos:pos+3], 2)
|
||
pos += 3
|
||
|
||
# RAIM标志 (1 bit)
|
||
decoded['RAIM标志'] = int(bit_string[pos], 2)
|
||
pos += 1
|
||
|
||
# 通信状态 (19 bits)
|
||
decoded['通信状态'] = int(bit_string[pos:pos+19], 2)
|
||
|
||
# 打印结果
|
||
print("\n编码字段的二进制表示:")
|
||
print(bit_string[:6] + " " + bit_string[6:8] + " " + bit_string[8:38] + " " +
|
||
bit_string[38:42] + " " + bit_string[42:50] + " " + bit_string[50:60] + " " +
|
||
bit_string[60:61] + " " + bit_string[61:89] + " " + bit_string[89:116] + " " +
|
||
bit_string[116:128] + " " + bit_string[128:137] + " " + bit_string[137:143] + " " +
|
||
bit_string[143:145] + " " + bit_string[145:148] + " " + bit_string[148:149] + " " +
|
||
bit_string[149:])
|
||
|
||
print("\n解码结果:")
|
||
print(f"消息ID: {decoded['消息ID']} (1=AIS消息1)")
|
||
print(f"转发指示符: {decoded['转发指示符']} (0=默认)")
|
||
print(f"用户ID (MMSI): {decoded['用户ID']}")
|
||
|
||
# 导航状态描述
|
||
nav_status_desc = {
|
||
0: "发动机使用中", 1: "锚泊", 2: "未操纵", 3: "有限适航性",
|
||
4: "受船舶吃水限制", 5: "系泊", 6: "搁浅", 7: "从事捕捞",
|
||
8: "航行中", 15: "未规定(默认)"
|
||
}
|
||
status = decoded['导航状态']
|
||
print(f"导航状态: {status} ({nav_status_desc.get(status, '未知状态')})")
|
||
|
||
# 旋转速率描述
|
||
rot = decoded['旋转速率']
|
||
if rot == -128:
|
||
rot_desc = "无可用旋转信息(默认)"
|
||
elif rot == 127:
|
||
rot_desc = "右旋超过5º/30s"
|
||
elif rot == -127:
|
||
rot_desc = "左旋超过5º/30s"
|
||
else:
|
||
# 计算实际旋转速度
|
||
rot_speed = (rot/4.733)**2 if rot != 0 else 0
|
||
direction = "右旋" if rot > 0 else "左旋"
|
||
rot_desc = f"{direction} {abs(rot_speed):.1f} 度/分钟"
|
||
print(f"旋转速率: {rot} ({rot_desc})")
|
||
|
||
# SOG描述
|
||
sog_val = decoded['SOG']
|
||
if sog_val == 1023:
|
||
sog_desc = "不可用"
|
||
elif sog_val == 1022:
|
||
sog_desc = "102.2节或更快"
|
||
else:
|
||
sog_desc = f"{sog_val/10:.1f} 节"
|
||
print(f"SOG: {sog_val} ({sog_desc})")
|
||
|
||
print(f"位置准确度: {decoded['位置准确度']} ({'高(>10m)' if decoded['位置准确度'] else '低(<10m)'})")
|
||
print(f"经度: {decoded['经度']:.5f}° ({'东经' if decoded['经度'] >= 0 else '西经'})")
|
||
print(f"纬度: {decoded['纬度']:.5f}° ({'北纬' if decoded['纬度'] >= 0 else '南纬'})")
|
||
|
||
# COG描述
|
||
cog_val = decoded['COG']
|
||
if cog_val == 3600:
|
||
cog_desc = "不可用(默认)"
|
||
else:
|
||
cog_desc = f"{cog_val/10:.1f}°"
|
||
print(f"COG: {cog_val} ({cog_desc})")
|
||
|
||
# 实际航向描述
|
||
heading = decoded['实际航向']
|
||
heading_desc = "不可用(默认)" if heading == 511 else f"{heading}°"
|
||
print(f"实际航向: {heading} ({heading_desc})")
|
||
|
||
# 时戳描述
|
||
ts = decoded['时戳']
|
||
ts_desc = {
|
||
60: "时戳不可用",
|
||
61: "人工输入模式",
|
||
62: "航迹推算模式",
|
||
63: "定位系统不起作用"
|
||
}.get(ts, f"{ts}秒")
|
||
print(f"时戳: {ts} ({ts_desc})")
|
||
|
||
# 特定操纵指示符描述
|
||
maneuver = decoded['特定操纵指示符']
|
||
maneuver_desc = {
|
||
0: "不可用(默认)",
|
||
1: "未进行特定操纵",
|
||
2: "进行特定操纵"
|
||
}.get(maneuver, "未知")
|
||
print(f"特定操纵指示符: {maneuver} ({maneuver_desc})")
|
||
|
||
print(f"备用: {decoded['备用']} (未使用)")
|
||
print(f"RAIM标志: {decoded['RAIM标志']} ({'RAIM正在使用' if decoded['RAIM标志'] else 'RAIM未使用(默认)'})")
|
||
print(f"通信状态: {decoded['通信状态']} (见表49)")
|
||
|
||
# 打印二进制字节
|
||
print("\n二进制字节表示 (168 bits = 21 bytes):")
|
||
hex_str = ' '.join(f'{b:02x}' for b in ais_data)
|
||
print(hex_str)
|
||
|
||
return ais_data
|
||
|
||
# 执行编码和解码
|
||
ais_binary = encode_ais_fields()
|
||
|
||
|
||
|
||
|
||
binary_str = "000001000001110101101111001101000101011000100000000001100110101000100111100110101111000000010001011100111100011000000011100001000010110100111100000000000000000000000000"
|
||
binary_int = int(binary_str, 2) # 将二进制字符串转换为整数
|
||
byte_length = (len(binary_str) + 7) // 8 # 计算需要的字节数
|
||
binary_data = binary_int.to_bytes(byte_length, 'big') # 转换为字节
|
||
|
||
print(binary_data) # 输出二进制数据 |