本周的物联网通信实验课上,需要我们编写部分HDB3编解码的c语言代码,个人觉得这个编解码的代码写得十分巧妙,还挺有意思的,故记录一下。
数字传输系统中传输的数字信息是来自计算机、电传机等数据终端的各种数字信号, 或者是来自模拟信号经数字化处理后的脉冲编码(PCM)信号等。这些数字信号所占据频谱 是从零频或低频开始,通常称为数字基带(baseband)信号。
在某些具有低通特性的有线信道中,特别是在传输距离不太远的情况下,基带信号可 以不经过载波调制而直接进行传输,这类系统称为数字基带传输系统。
基带传输系统中,并不是所有的基带波形都适合在信道中传输,需要转换基带码型再 进行传输。HDB3 则是一种常用的基带传输码型。
HDB3 码编码规则如下:
(1)当消息码中连“0”数目小于等于 3 时,非“0”脉冲极性交替;例如:
消息码: 1 0 0 1 0 0 0 1
HDB3码: -1 0 0 +1 0 0 0 -1
(2)当消息码中连“0”数目超过 3 个时,将每 4 个连“0”化作一小节,定义为 B00V,称为 破坏节,其中 V 称为破坏脉冲,而 B 称为调节脉冲。
(3)V 与其前一个的非“0”脉冲的极性相同(这破坏了极性交替的规则,所以 V 称为破坏脉冲),并且要求相邻的 V 码之间极性必须交替。V 的取值为+1 或-1。
(4)B 的取值可选 0、+1 或-1。
(5)V 码后面的传号码极性也要交替。例如:
消息码: 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1
HDB3 码: -1 0 0 0 -V +1 0 0 0 +V -1 +1 -B 0 0 -V +B 0 0 +V -1 +1
我们先稍微整理一下HDB3的编码规则:
(1)当连 0 个数不超过 3 时,非“0”脉冲极性交替。
(2)当连 0 个数超过 3 时,检查两个相邻的 V 码之间的 1 的个数,如果有奇数个 1 时,此四个连 0 用 000V 表示,如果有偶数个 1 时,此四个连 0 用 B00V 表示。
(3)1 与 B 一起确定极性,即相当于把 B 看做 1,1 与 B 一起极性交替。
(4)V 码的极性与前一个非 0 码(含 B 码)极性相同,之后保证 V 码 极性交替即可。
代码实现:
编写代码时我们主要需要解决两个问题:一个是非0码的极性,一个是准确区别B00V和000V两种情况。
我们先来就以下这段消息码逐个进行编码,理解一下我们的代码实现思路。
我们可以看到,靠存储b和v这两个标志位,我们就能够轻松解决非0码的极性和区别B00V和000V两种情况的问题。个人觉得这个代码实现思路还是十分巧妙的!简洁且优雅地解决了一个较为复杂的问题!值得回味!
以下是我使用c++实现的HDB3编码代码:
#include<iostream> using namespace std; int b = 1; // 标志位,代表上一个非0码(不含v码)的极性 int v = 1; // 标志位,与标志位b配合克用于判断相邻两个v码间有奇数还是偶数个1 int i = 0; int main() { int n; cout << "请输入消息码长度:" << endl; cin >> n; int* in = new int[n]; int* out = new int[n]; cout << "请输入消息码:" << endl; for (; i < n; i++) { cin >> in[i]; } // HDB3编码 i = 0; while (i < n) { if (in[i] == 1) //若消息码为1,交替为+1,-1 { out[i] = -1 * b; b = out[i]; i = i + 1; } else if (in[i + 1] == 1) //消息码只有一个0 { out[i] = 0; out[i + 1] = -1 * b; b = out[i + 1]; i = i + 2; } else if (in[i + 2] == 1) //消息码有两个连续0 { out[i] = 0; out[i + 1] = 0; out[i + 2] = -1 * b; b = out[i + 2]; i = i + 3; } else if (in[i + 3] == 1) //消息码有三个连续0 { out[i] = 0; out[i + 1] = 0; out[i + 2] = 0; out[i + 3] = -1 * b; b = out[i + 3]; i = i + 4; } else if (b ^ v) // b,v标志不同,即表示两个v码间间隔了奇数个1 { out[i] = 0; out[i + 1] = 0; out[i + 2] = 0; out[i + 3] = b; v = b; i = i + 4; } else //b,v标志相同,即表示两个v码间间隔了偶数个1 { out[i] = -1 * b; b = out[i]; out[i + 1] = 0; out[i + 2] = 0; out[i + 3] = -1 * v; v = out[i + 3]; i = i + 4; } } cout << "HDB3编码为:" << endl; for (i = 0; i < n; i++) { cout << out[i] << " "; } cout << endl; }
运行结果:
HDB3的编码相对比较复杂,但是HDB3的解码就简单很多了。
若HDB3码为0,那么原消息码肯定为0。
我们主要需要解决的问题就是找出HDB3码中的v码,v码前面三个码必是三个0。再将其余的-1变成+1便可得到原消息码。
以下是我用c++实现的HDB3解码:
#include<iostream> using namespace std; int main() { int cnt_0 = 0; //记录连续0的个数 int polarity = 0; //记录前一个信码的极性 int n; cout << "请输入HDB3码长度:" << endl; cin >> n; int* in = new int[n]; int* out = new int[n]; cout << "请输入HDB3码:" << endl; for (int i = 0; i < n; i++) { cin >> in[i]; } // HDB3解码 for (int i = 0; i < n; i++) { if (!(in[i])) //HDB3码为0,译码结果一定是0 { cnt_0++; out[i] = 0; } else //HDB3码不为0 { if ((in[i] == polarity) && (cnt_0 >= 2)) //当前HDB3码是+V或-V { out[i] = 0; if (cnt_0 == 2) //若+V或-V前面是连续两个0,则该段HDB3码为B00V,原消息码是连续4个0,应还原前一个B码为0 { out[i - 3] = 0; } } else //当前HDB3码是非0码(不包含v码) { out[i] = 1; // 记录前一个非0码(不包含v码)的极性 if (in[i] == -1) { polarity = -1; } else { polarity = 1; } } cnt_0 = 0; } } cout << "HDB3解码为:" << endl; for (int i = 0; i < n; i++) { cout << out[i] << " "; } cout << endl; }
运行结果: