前言
本篇文章主要介绍了HDB3码的基本规则,相关的解码、编码方法,以及用MATLAB实现。最终的目的是使用Verilog语言完成一个HDB3的编码器和译码器。
一、HDB3 码是什么?
HDB3全称(High Density Bipolar of order 3 code,三阶高密度双极性码)在学习通信原理这门课的时候有了解到这样的编码方式,但时间久远,我甚至连名字都记不起来了。我们可以简单的看一下HDB3码的百度百科。可以看到HDB3码是对AMI码的一个进阶。下面就了解一下编码规则以及机器实现的简便方法。
1.编码规则
了解编码规则之前,先了解一下其中的关键名词。
- V:破坏脉冲。
- B:调节脉冲。
- B00V:取代节、破坏节。
再了解随后的编码步骤:
第一步:连0的个数不超过3时,规则与AMI相同,即0不变,1变为-1、+1交替;
第二步:若连0的个数超过3,则将每4个0看作一小节,定义为B00V,B可以是-1、0、+1,V可以是-1、+1;
第三步:B和V具体值满足以下条件:V和前面相邻非0符号极性相同;不看V时极性交替;V与V之间极性交替;
第三步:一般第一个B取0,第一个非0符取-1;
为什么第一个B总是0那?这里可以根据B和V的含义来理解。V(破坏脉冲)的出现将1的交替打乱,并且V的极性也要交替正负。有时这两个条件不能同时满足,就需要B了。B(调节脉冲)应该和1的极性看成一组,保证极性交替正负。而第一个V的极性保持和上一个1的极性相同,不需要B的调节。
再举一个例子,就能更加清楚地明白了。
消息代码:1 0 0 0 0 1 0 0 0 01 1 0 0 0 0 1 1
AMI码: -1 0 0 0 0 +1 0 0 0 0 -1 +1 0 0 0 0 -1 +1
HDB3码:-1 0 0 0 -V +1 0 0 0 +V -1 +1 -B 0 0 -V +1 -1
2.总结经验方法
了解了基本的编码规则,手算的方法有很多, 细心总能得到最后的结果。但是对于机器而言,应该有一种比较简单的方法,下面就介绍一下适合机器的编码方法。
1、源码是1时,暂时不变;
2、连0不超过3个时不变,有4个或以上连0时把每4个0换为取代节,即B00V;
3、确定B是0还是±1:第一个B一般取0,若两个取代节之间1的个数为偶,易推得后者的B一定是±1,此时B和1遵循的规则完全相同,可以直接记为1,即100V;为奇则一定是0,记为0,即000V。
4、统一确定极性:第一个非0符一般取-1,之后,根据前一个非0符极性,V取同,1取反;
二、MATLAB 实现HDB3编码和解码
1.实现HDB3的编码
我是按照这个步骤自己一步一步写的,效率比较低,网上有很多效率很高的代码,大家也可以去学习。
准备工作
%给出一个源码
Sn = [ 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 1 ];
n = length(sn);
codeSn = Sn;
第一步:找出源码中的取代节 V用2表示 B用3表示
count = 0; %用来记录 连0 的个数
for i = 1:n
if(codeSn(i) == 1)
count = 0; %遇到1 连0的计数器清零
else
count = count + 1;
if count == 4 % 0000 转成 取代节
codeSn(i) = 2;
codeSn(i-3) = 3;
count = 0; %计数清零
end
end
end
结果:
Sn = [ 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 1 ];
codeSn = [1 3 0 0 2 1 3 0 0 2 1 1 3 0 0 2 1 1];
可以看到四个连0 全部变成了取代节 3002 也就等价于 B00V。
第二步:处理取代节中B的值
flagB = 1;
count_1 = 0;
pV = 0;
pB = 0;
for i = 1:n
if (codeSn(i) == 3) && (flagB == 1) %将第一个B 置 0
codeSn(i) = 0;
flagB = 0;
end
if codeSn(i) == 2 %找到前一个取代节的V
pV = i;
else if codeSn(i) == 3 %找到后一个取代节的B
pB = i;
end
end
if(pB > pV)
for j = pV+1 : pB-1 %不要将B 和 V的值包含进去
count_1 = count_1 + codeSn(j); %计算两个之间 1 的个数
end
if mod(count_1 , 2) == 1 %奇数个
codeSn(pB) = 0;
else
codeSn(pB) = 1; %偶数个
end
%将变量归零,等待下一次找两个取代节的成功
pV = 0;
pB = 0;
count_1 = 0;
end
end
这一步的过程我写的太过于复杂。这要的功能是两个。
第一个:将第一个B转成0.
第二个:找到后一个取代节和前一个取代节之间1的个数,奇数个就将B变成0,偶数个就变成 1.
结果:codeSn =[1 0 0 0 2 1 0 0 0 2 1 1 1 0 0 2 1 1]
可以看到其中第一个B转成了0,后续一个变成了0,一个变成1;
第三步:%统一确定极性
%统一确定极性
even = 0; % 用来翻转 1 的极性
evenV = 0;% 用来翻转 V 的极性
for i = 1:n
if codeSn(i) == 1
codeSn(i) = -1; %第一个 1 转成 -1
break;
end
end
for i = 1:n
if codeSn(i) == 1 %将 1 的极性正负翻转
if even == 0
codeSn(i) = 1;
else
codeSn(i) = -1;
end
even = ~even;
else if codeSn(i) == 2 %将 V 的极性正负翻转 同时变回 数值 1
evenV = even; %第一个V的极性与前一个非零符号相同
if evenV == 0
codeSn(i) = -1;
else
codeSn(i) = 1;
end
evenV = ~evenV;
end
end
end
通过这一步来实现极性的全部分配,B在上一步已经全部变成1了,只要将1的极性正负交替就行。V的极性也要正负交替,第一个也给他整成-1能保持,V的两个特性了:1.自身极性交替。2.与前一个非0符号的极性相同。
结果:codeSn =[-1 0 0 0 -1 1 0 0 0 1 -1 1 -1 0 0 -1 1 -1];
到这里编码已经完成。下面将源码的图像和编码后的图像,打印出来,看一看区别。
实现代码:
%绘图部分
figure(1);
subplot(2,1,1);
stairs(0:length(Sn)-1,Sn);
axis([0 length(Sn) -2 2]);
title('源码图'); grid; %打开网格
subplot(2,1,2);
stairs(0:length(codeSn)-1,codeSn);
axis([0 length(codeSn) -2 2]);
title('hdb3编码图'); grid; %打开网格
显示结果:
2.实现HDB3的解码
完成hdb3的编码之后,下一步就是进行解码。解码的方式根据百度百科的介绍就可以,相对于编码,解码的过程比较简单。
- 把原来的取代节(4个连零)找到即可,若3连“0”前后非零脉冲同极性,则将最后一个非零元素译为零,如+1000+1 就应该译成“10000”,否则不用改动;若2连 “0”前后非零脉冲极性相同,则两零前后都译为零,如-100-1,就应该译为0000,否则也不用改动.
- 再将所有的-1变换成+1后,就可以得到原消息码。
%hdb3 解码部分
Sn = [-1 0 0 0 -1 1 0 0 0 1 -1 1 -1 0 0 -1 1 -1 ];
dchdbn = Sn; %定义一个输出数组
count = 0;
for j = 1 : length(Sn)
if Sn(j) == 0
count = count + 1;
if count == 3 %若3连“0”前后非零脉冲同极性,则将最后一个非零元素译为零
if dchdbn(j + 1) * dchdbn(j - 3) == 1
dchdbn(j + 1) = 0;
end
end
if count == 2 %若2连 “0”前后非零脉冲极性相同,则两零前后都译为零
if dchdbn(j + 1) * dchdbn(j - 2) == 1;
dchdbn(j - 2) = 0;
dchdbn(j + 1) = 0;
end
end
else
count = 0;
end
end
%极性变换
for n = 1 : length(Sn) %再将所有的-1变换成+1后,就可以得到原消息代码
if dchdbn(n) == -1
dchdbn(n) = 1;
end
end
结果:dchdbn = [1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 1];
这里就不绘图展示最后的结果了。
总结
总而言之,hdb3的编码规则就是这样,具体如何实现,看自己的思路了。之前学习过matlab但是,使用的次数不多,其中有很多功能还不知道。多多练习才是最近的捷径。MATLAB的仿真就是这样下面进行FPGA中的实验。将语言的风格转变为并行风格,又需要怎么样的编程思路那?
已经根据评论做出指正(2021.11.13)。