AIS解码算法

AIS的信息内容是经过压缩的,压缩的方法比较特殊,因为要求压缩的结果是可见字符。本文针对压缩以及解压缩进行描述。

 

对于VDM消息中的压缩码,编码格式是根据以下对照表来进行的。制定这种编码格式的目的一是为了压缩信息内容,二是要求压缩以后的信息能够以ASCII码显示,以便使用文本方式传输(如果直接压缩,可能会产生不可见字符,这就是一般压缩文件以二进制方式存储的原因)。

ASCII
HEX = binary
Valid Character
Binary Field represented
ASCII
HEX = binary
Valid Character
Binary Field represented
30=00110000
0
000000
50=01010000
P
100000
31=00110001
1
000001
51=01010001
Q
100001
32=00110010
2
000010
52=01010010
R
100010
33=00110011
3
000011
53=01010011
S
100011
34=00110100
4
000100
54=01010100
T
100100
35=00110101
5
000101
55=01010101
U
100101
36=00110110
6
000110
56=01010110
V
100110
37=00110111
7
000111
57=01010111
W
100111
38=00111000
8
001000
60=01100000
101000
39=00111001
9
001001
61=01100001
a
101001
3A =00111010
:
001010
62=01100010
b
101010
3B=00111011
;
001011
63=01100011
c
101011
3C =00111100
001100
64=01100100
d
101100
3D=00111101
=
001101
65=01100101
e
101101
3E=00111110
001110
66=01100110
f
101110
3F =00111111
?
001111
67=01100111
g
101111
40=01000000
@
010000
68=01101000
h
110000
41=01000001
A
010001
69=01101001
i
110001
42=01000010
B
010010
6A =01101010
j
110010
43=01000011
C
010011
6B=01101011
k
110011
44=01000100
D
010100
6C =01101100
l
110100
45=01000101
E
010101
6D=01101101
m
110101
46=01000110
F
010110
6E=01101110
n
110110
47=01000111
G
010111
6F =01101111
o
110111
48=01001000
H
011000
70=01110000
p
111000
49=01001001
I
011001
71=01110001
q
111001
4A =01001010
J
011010
72=01110010
r
111010
4B=01001011
K
011011
73=01110011
s
111011
4C =01001100
L
011100
74=01110100
t
111100
4D=01001101
M
011101
75=01110101
u
111101
4E=01001110
N
011110
76=01110110
v
111110
4F =01001111
O
011111
77=01110111
w
111111

 
目前我们只需要考虑使用以上编码格式进行解码就可以了。以下是解码流程。
1.Convert ASCII-code to 6-bit binary field(将ASCII码转换成6位二进制值)

算法图例:

   

 

 

 

第一个判断是因为经过编码的文本字符只可能为0x30到0x77间的可显示字符。
第二个判断与第三个判断是由于在编码表中,我们可以看到,0x57以后并不是0x58,而是0x60,所以在0x58到0x5F间的字符是无效字符。
以上三个判断是对需要解码的字符有效性的判断。
其下的流程是真正的解码流程。至于为什么用这样的流程,大家可以推敲,目前我们只需安照该流程执行,即可将VDM消息中的压缩信息转为6比特的信息了。
 
解码算法代码:
//转换单个字符
bool EightByteToSix(BYTE inEight,BYTE &outSix)
{
//以下两个判断用于检测所输入的ASCII码是否有效
       if(inEight < 0x30 || inEight > 0x77)
              return false;
       if(inEight > 0x57 && inEight < 0x60)
              return false;
//检查结束
       outSix = inEight + 0x28;    //加上101000
       if(outSix > 0x80)          //如果SUM>10000000
              outSix += 0x20;       //加上100000
       else
              outSix += 0x28;       //加上101000
       outSix = outSix<<2;       //右移两位,获取LSB
       return true ;
}
//转换整个压缩信息
2. Convert ASCII-code String to 6-bit binary field Array (将ASCII 码字符串转换成6 位二进制值表示的字符数组)
说明:将每个ASCII 码转换成6bits 码后,因为数据是以字节为单位保存的,因此需要将这些6bits 码放置到字节中去。比如ASCII 码串”A2L9” ,转换成6bits 二进制是这样的:010001 000010 011100 001001 。用字节表示就是 01000100 00100111 00001001 即0x44,0x27,0x09 这三个ASCII 码。
算法代码:
//返回参数用LPBYTE而不用CString,是因为转换的数据中可能出现0x00。这在字符串中会作为串结束符看待,因此将无法得到串的真实长度
bool EightStrToSix(CString inEight, LPBYTE outSix)
{
       BYTE len = inEight.GetLength();
       BYTE nowBt = 0x00;//用于记录当前未用完的记录6Bits码的字节
       BYTE midBt;//中间转换记录字节
       BYTE outLen = 0;
       for(int i=0;i<len;i++)//处理所有ASCII码
       {
              BYTE bt = inEight.GetAt(i);
              BYTE six;
              If(EightByteToSix(bt,six)==false)//将当前ASCII码转换成6 bits码
              return false;
              int res = i%4;//因为4个ASCII码转换成3个字节的6bits码,因此将是每4个ASCII码的转换成为一个循环过程
              switch(res)
              {
//当是第一个ASCII码时,不能直接完成一个6bits码的字节转换,因为还有两个bits没有填入数据。用nowBt暂先保存6bits码正在记录数据的字节
              case 0:
                     nowBt = six;
                     break;
//当处理第二个ASCII码时,显然,加上第一个ASCII码的转换,2个6bits码将是12bits,因此可以完成一个字节的数据,另外余下的4bits记录到nowBt中,等待下一个ASCII码的处理。
              case 1:
                     midBt = six >>6; //将最高的两位移到末尾,以便将高二位保存到nowBt的低二位中
                     nowBt = nowBt | midBt;//完成6bits码的第一个字节
                     outSix[outLen] = nowBt;//保存到输出的字节数组中
                     outLen ++;
                     //以下两步移位是将当前6bits码的中间4位移动到高四位中。并记录到nowBt中。
                     nowBt = six >>2;
                     nowBt = nowBt <<4;
                     break;
//当处理第三个ASCII码时,nowBt中的有效位是高四位,因此需要将新的6bits码的高四位放到nowBt的低四位中,然后保存nowBt到输出数组,再将新的6bits码的第5,6位移到高二位后记录到nowBt中
              case 2:
                     midBt = six >>4;//将高四位移到低四位
                     nowBt = nowBt | midBt;//完成6bits码的第二个字节
                     outSix[outLen] = nowBt;//保存到输出的字节数组
                     outLen ++;
//将新的6bits码的第5,6位移到高二位后记录到nowBt中
                     nowBt = six >>2;
                     nowBt = nowBt <<6;
                     break;
              //当处理第四个ASCII码时,nowBt中的有效位是高二位,因此将新的6bits码的高6位移到nowBt的低6位,正好完成一个循环
              case 3:
                     midBt = six >>2;//将高六位移到低六位
                     nowBt = nowBt | midBt;//完成6bits码的第三个字节
                     outSix[outLen] = nowBt;//保存到输出的字节数组
                     outLen ++;
                     nowBt = 0x00;//nowBt复位
                     break;
              }
              default:
{
break;
}
       }
       return true;
}
 
信息获取代码
压缩信息解码完成后,就可以从解码信息中读取指定的内容了。
根据读取的信息的比特长度不同,读取的方法也有所变化。
3. 从解码数据中获取指定类型的数据内容
3.1获取1bits 到 8bits的整数数据
//lpInfo—调用EightStrToSix获取的解码数据
//dwBitStart –需要获取的数据的起始位. dwBitStart 从0开始
//byLen –数据所占位数
BYTE GetByteValFromInfo(const LPBYTE lpInfo,DWORD dwBitStart,BYTE byLen)
{
       BYTE byStartByte = dwBitStart/8;//获取起始字节序号
       BYTE byStartBit = dwBitStart%8;//获取起始字节中的起始位数
       BYTE byInfo = 0x00;
       if(8-byStartBit < byLen)//要获取的数据跨两个字节
       {
              BYTE by1 = *(lpInfo + byStartByte);//获取第一个字节数据
              BYTE by2 = *(lpInfo + byStartByte + 1);//获取第二个字节数据
              //完成两个字节中位的拼接
              by1 = by1 << byStartBit;
              by1 = by1 << 8 - byLen;   //byLen - (8 - byStartBit)
              by2 = by2 >> 16 - byLen - byStartBit; //8 - (byLen - (8 - byStartBit))
              byInfo = by1 | by2;
       }
       else
       {
              byInfo = *(lpInfo + byStartByte);
              byInfo = byInfo << byStartBit;
              byInfo = byInfo >> 8 - byLen;
       }
       return byInfo;
}
3.2获取9bits 到 16bits的整数数据
WORD GetWordValFromInfo(const LPBYTE lpInfo,DWORD dwBitStart,WORD wLen)
{
       BYTE byStartByte = dwBitStart/8;
       BYTE byStartBit = dwBitStart%8;
       WORD wInfo = 0x0000;
       if(16 - byStartBit < wLen)//要获取的数据跨三个字节
       {
              wInfo = *(WORD*)(lpInfo + byStartByte);
              wInfo = wInfo << byStartBit;
              wInfo = wInfo >> 16 - wLen;
              BYTE by1 = *(lpInfo + byStartByte + 2);
              by1 = by1 >> 24- wLen - byStartBit;
              wInfo = wInfo | by1;
       }
       else
       {
              wInfo = *(WORD*)(lpInfo + byStartByte);
              wInfo = ntohs(wInfo);
              wInfo = wInfo << byStartBit;
              wInfo = wInfo >> 16 - wLen;
       }
       return wInfo;
}
 
3.3获取17bits 到 32bits的整数数据
DWORD GetDWordValFromInfo(const LPBYTE lpInfo,DWORD dwBitStart,DWORD dwLen)
{
       BYTE byStartByte = dwBitStart/8;
       BYTE byStartBit = dwBitStart%8;
       DWORD dwInfo = 0x00000000;
       if(dwLen <= 24)//占三个或者四个字节
       {
              if(24 - byStartBit < dwLen)//占四字节
              {
                     dwInfo = *(DWORD*)(lpInfo + byStartByte);
                     dwInfo = ntohl(dwInfo);
                     dwInfo = dwInfo << byStartBit;
                     dwInfo - dwInfo >> 32 - dwLen;
              }
              else //占三字节
              {
                     DWORD dwInfo = 0x00FFFFFF;
                     dwInfo = dwInfo & *(DWORD*)(lpInfo + byStartByte - 1);
                     dwInfo = ntohl(dwInfo);
                     dwInfo = dwInfo << byStartBit;
                     dwInfo = dwInfo >> 24 - dwLen;
              }
       }
       else//占四个或者五个字节
       {
              if( (32 - byStartBit) < dwLen)//占五个字节
              {
                     dwInfo = *(DWORD*)(lpInfo + byStartByte);
                     dwInfo = ntohl(dwInfo);
                     dwInfo = dwInfo << byStartBit;
                     dwInfo = dwInfo >> 32 - dwLen;
                     BYTE by1 = *(lpInfo + byStartByte + 4);
                     by1 = by1 >> 40 - dwLen - byStartBit;
                     dwInfo = dwInfo | by1;
              }
              else//占四个字节
              {
                     dwInfo = *(DWORD*)(lpInfo + byStartByte);
                     dwInfo = ntohl(dwInfo);
                     dwInfo = dwInfo << byStartBit;
                     dwInfo = dwInfo >> 32 - dwLen;
              }
       }
       return dwInfo;
}
 
3.4获取字符串类型数据
CString GetStringValFromInfo(const LPBYTE lpInfo, DWORD dwBitStart, DWORD dwLen)
{
       WORD wChars = dwLen/6;
       BYTE byStartByte = dwBitStart/8;
       BYTE byStartBit = dwBitStart%8;
       CString sRtnStr;
      
       for(WORD wChar = 0; wChar < wChars; wChar++)
       {
              BYTE byChar = *(lpInfo + byStartByte);
              byChar = byChar << byStartBit;
              byChar = byChar >> 2;
              if(byStartBit > 2)//表示该BYTE数据跨字节了
              {
                     BYTE by1 = *(lpInfo + byStartByte + 1);
                     by1 = by1 >> 16 - 6 - byStartBit;
                     byChar = byChar | by1;
                     byStartByte ++;
                     byStartBit = byStartBit - 2;
              }
              else
              {
                     byStartBit += 6;
                     if(byStartBit == 8)
                     {
                            byStartBit = 0;
                            byStartByte ++;
                     }
              }
              //字符串解码,如果小于0x20,需要加上0x40
              //具体规则参考ITU-R M-1371-1文件第41,42页
              if(byChar < 0x20)
                     byChar += 0x40;
              sRtnStr += byChar;
       }
       return sRtnStr;
}
 
### 回答1: AIS是自动识别系统,可以用于船舶识别和定。由于AIS信息的编码格式复杂,因此需要针对AIS信息进行解码才能获取有用的数据。Matlab是一种功能强大的数学软件,可以用于数据处理和分析。 使用Matlab进行AIS解码需要安装相应的工具箱和库,例如AIS Toolbox和Spatial Toolbox等。这些工具可以提供AIS信息的解码功能和数据处理的工具。 对于AIS信息的解码,首先要对接收到的二进制数据进行解码。这个过程经过多次反和解析,最终得到AIS信息的ASCII码。然后将ASCII换为可识别的文本格式,例如船名、MMSI号码、船舶类型等。最终,这些数据可以在Matlab中进行处理和分析,例如绘制船只轨迹、计算船只速度等。 需要注意的是,AIS解码涉及到复杂的技术和算法,需要有相关领域的知识和经验。因此,使用Matlab进行AIS解码需要专业人员操作,确保数据的准确性和可靠性。 ### 回答2: 人工智能语音识别技术(AIS)是目前比较流行的一种语音识别技术,可以将人类语言化成计算机能够理解的数字信号。在语音信号解码中,Matlab是一个常用的工具,可以实现语音信号的处理和分析等功能。 在实现AIS解码过程中,需要做的就是将输入的语音信号化为数字信号,然后再通过算法进行处理,最终得到语音信号的文本信息。一般情况下,AIS解码过程主要包括以下几个步骤: 首先是预处理,这个过程主要是为了将语音信号进行数字化处理。这可以通过使用Matlab中的信号处理工具箱进行实现,进行语音的采样、滤波、预加重等处理。 接着是语音特征提取,这个过程主要是为了从数字化处理后的信号序列中提取出有意义的语音信息。这个过程需要通过使用Mel-Frequency Cepstral Coefficients (MFCCs)等特征来进行实现。 然后就是声学模型训练,这个过程主要是为了通过机器学习算法训练出能够将语音信号换成文本信息的声学模型。这个过程需要通过使用Matlab中的神经网络或支持向量机等算法来实现。 最后就是解码过程,这个过程是将声学模型应用到实际语音信号中,从而得到相应的文本信息。这个过程需要通过使用Viterbi算法解码算法来实现。 总之,AIS解码Matlab这个过程需要结合语音信号处理和机器学习算法等技术手段,从而实现语音信号的换和文本信息的提取。需要注意的是,在实际应用过程中,需要根据具体情况进行调整和优化,从而达到更好的识别效果。 ### 回答3: AI是近年来非常火热的一个领域,也是一个非常重要的技术方向,而MATLAB是一款非常流行的科学计算软件,其中包含了非常强大的矩阵运算和统计分析工具。在AI的领域中,有一个非常重要的技术就是AI语音识别,而AIS解码MATLAB就是AI语音识别中的一种常用的解码方法。 AIS解码MATLAB是一种人工智能语音识别技术,它是通过将语音进行数字化处理,将其化为矩阵形式,然后利用MATLAB中的矩阵运算和统计分析工具,分析语音中的特征,来对语音进行识别的。这个方法基于人的声音特征和语音语法的分析,取得了非常好的效果,已经广泛应用于语音识别、语音指令、智能语音交互等领域。 AIS解码MATLAB方法的核心是通过MATLAB中的矩阵运算和统计分析工具来对语音信号进行特征提取,然后使用传统的模式识别算法,例如深度学习、卷积神经网络等来进行识别。由于MATLAB具有直观便捷的编程语言和强大的矩阵运算能力,因此这个方法非常适合初学者进行学习和应用。 总之,AIS解码MATLAB是一种非常实用、高效的人工智能语音识别技术,它具有很高的准确率和广泛的应用范围。通过对语音进行数字化处理,然后利用MATLAB中强大的矩阵运算和统计分析工具来分析语音特征,可以实现高效的语音识别。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值